"use strict";
顧名思義也就是 JavaScript 會在所謂嚴格模式下執行,其一個主要的優點在於可以強制開發者避免使用未聲明的變量。對於老版本的瀏覽器或者執行引擎則會自動忽略該指令。javascript
在正常模式中,若是一個變量沒有聲明就賦值,默認是全局變量。嚴格模式禁止這種用法,全局變量必須顯式聲明。html
"use strict"; v = 1; // 報錯,v未聲明 for(i = 0; i < 2; i++) { // 報錯,i未聲明 }
所以,嚴格模式下,變量都必須先用var命令聲明,而後再使用。java
Javascript語言的一個特色,就是容許"動態綁定",即某些屬性和方法到底屬於哪個對象,不是在編譯時肯定的,而是在運行時(runtime)肯定的。
嚴格模式對動態綁定作了一些限制。某些狀況下,只容許靜態綁定。也就是說,屬性和方法到底歸屬哪一個對象,在編譯階段就肯定。這樣作有利於編譯效率的提升,也使得代碼更容易閱讀,更少出現意外。程序員
由於下面的代碼不是在嚴格模式下執行,而且this的值不會在函數執行時被設置,此時的this的值會默認設置爲全局對象。segmentfault
function f2(){ "use strict"; // 這裏是嚴格模式 return this; } f2() === undefined; // true
更全面的信息參考這個連接瀏覽器
考慮下面程序的運行結果ide
var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar();
結果是10;
再看下面這個函數
var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a);
結果是1this
出乎意料的結果是因爲「Hoisting (變量提高)」的緣由,要理解其中的原理須要先了解下JavaScript的做用域scope。.net
javascript做用域(函數做用域)與C語言做用域(塊級做用域)不一樣
int main() { int x = 1; printf("%d, ", x); // 1 if (1) { int x = 2; printf("%d, ", x); // 2 } printf("%d\n", x); // 1 }
這是由於C家族的語言有塊做用域,當程序控制走進一個塊,好比if塊,只做用於該塊的變量能夠被聲明,而不會影響塊外面的做用域。可是在Javascript裏面,這樣不行
var x = 1; console.log(x); // 1 if (true) { var x = 2; console.log(x); // 2 } console.log(x); // 2
函數聲明和變量聲明老是會被解釋器悄悄地被「提高」到方法體的最頂部。這個意思是,像下面的代碼:
function foo() { bar(); var x = 1; }
實際上會被解釋成:
function foo() { var x; bar(); x = 1; }
不管定義該變量的塊是否能被執行。下面的兩個函數其實是一回事:
function foo() { if (false) { var x = 1; } return; var y = 1; } function foo() { var x, y; if (false) { x = 1; } return; y = 1; }
只有函數式的聲明纔會連同函數體一塊兒被提高。foo的聲明會被提高,可是它指向的函數體只會在執行的時候才被賦值
function test() { foo(); // TypeError "foo is not a function" bar(); // "this will run!" var foo = function () { // 變量指向函數表達式 alert("this won't run!"); } function bar() { // 函數聲明 函數名爲bar alert("this will run!"); } } test();
若是程序員不能很好的理解變量提高,他們寫的程序就容易出現一些問題。
爲了不這些問題,一般咱們在每一個做用域開始前聲明這些變量,這也是正常的 JavaScript 解析步驟,易於咱們理解。
JavaScript 嚴格模式(strict mode)不容許使用未聲明的變量。
function Person (name,age) { this.name = name; this.age = age; this.type = "human"; this.play = function(){console.log("video game")}; } //下面生成實例 var Person1 = new Person("Tom",25); var Person2 = new Person("Jack",26); alert(Person1.name); //這時Person1和Person2會自動含有一個constructor屬性,指向它們的構造函數。 alert(Person1.constructor); //Javascript還提供了一個instanceof運算符,驗證原型對象與實例對象之間的關係 alert(Person1 instanceof Person); //true alert(Person1.type == Person2.type);//ture alert(Person1.play == Person2.play);//false
type屬性和play()方法都是如出一轍的內容,每一次生成一個實例,都必須爲重複的內容,多佔用一些內存.
Javascript規定,每個構造函數都有一個prototype屬性,指向另外一個對象。這個對象的全部屬性和方法,都會被構造函數的實例繼承。
這意味着,咱們能夠把那些不變的屬性和方法,直接定義在prototype對象上.
function Person (name,age) { this.name = name; this.age = age; } Person.prototype.type = "human"; Person.prototype.play = function(){console.log("video game")}; var Person1 = new Person("Tom",25); var Person2 = new Person("Jack",26); alert(Person1.type); //human alert(Person1.play == Person2.play); //true
這時全部實例的type屬性和play()方法,其實都是同一個內存地址,指向prototype對象,使用原型的好處是可讓對象實例共享它所包含的屬性和方法,所以就提升了運行效率。
在JavaScript中,一共有兩種類型的值,原始值和對象值。每一個對象都有一個內部屬性 prototype ,咱們一般稱之爲原型。原型的值能夠是一個對象,也能夠是null。若是它的值是一個對象,則這個對象也必定有本身的原型。這樣就造成了一條線性的鏈,咱們稱之爲原型鏈。
關於原型、原型鏈-猛戳
ECMAScript 有 5 種原始類型(primitive type),即 Undefined、Null、Boolean、Number 和 String。
原始數據類型
引用類型一般叫作類(class),也就是說,遇到引用值,所處理的就是對象。
Object 對象
Object 對象自身用處不大,不過在瞭解其餘類以前,仍是應該瞭解它。由於 ECMAScript 中的 Object 對象與 Java 中的 java.lang.Object 類似,ECMAScript 中的全部對象都由這個對象繼承而來,Object 對象中的全部屬性和方法都會出如今其餘對象中,因此理解了 Object 對象,就能夠更好地理解其餘對象。
Object 對象具備下列屬性
constructor
對建立對象的函數的引用(指針)。對於 Object 對象,該指針指向原始的 Object() 函數。
Prototype
對該對象的對象原型的引用。對於全部的對象,它默認返回 Object 對象的一個實例。
全部程序設計語言最重要的特徵之一是具備進行類型轉換的能力。
ECMAScript 給開發者提供了大量簡單的類型轉換方法。