最近,在讀《你不知道的JavaScript(上卷)》這本書,書中詳細闡述了JavaScript眾多重要但經常被大家忽略的點,在此強烈推薦。。。書中,第4章講述了“提升”,從樣本出發講述了變數和函數提升的過程,糾正了自己以前錯誤的理解(相信好多人理解都是錯誤)。
我們習慣將var a = 2;看做一個聲明,而實際上JavaScript引擎不這麼認為。下面幾個樣本讓你徹底搞懂JavaScript中的變數提升。
樣本1:
a = 2;var a ;console.log(a);//2
樣本2:
console.log(b); //undefinedvar b = 2;
樣本3:
var c;console.log(c);//undefinedc = 2;
樣本4:
foo();function foo(){console.log(d);//undefinedvar d = 2;}
樣本5:
bar();//TypeErrorvar bar = function too(){// ....}
樣本6:
aoo();//TypeErrorboo();//ReferenceErrorvar aoo = function boo(){// ...}
樣本7:
function foo(){console.log(1);}foo();//1foo = function(){console.log(2);};
樣本8:
foo();//3function foo(){console.log(1);}var foo = function(){console.log(2);};function foo(){console.log(3);}
樣本9:
foo();//bvar a = true;if(a){function foo(){ console.log("a"); }}else{function foo(){ console.log("b"); }}
注意:這個行為並不可靠,在JavaScript未來的版本中有可能發生改變,因此應該儘可能避免在塊內部聲明函數。 總結:
1. var a = 2;其中var a在編譯階段,a=2在執行階段;
2. 無論範圍中的聲明(變數和函數)出現在什麼地方,都將在代碼本身執行前首先進行處理;
3. 聲明本身會被提升,而包括函數運算式的賦值在內的賦值操作並不會提升;
4. 函數會首先被提升,然後才是變數,重複的var(變數)聲明會被忽略掉;
5. 後面的函式宣告可以覆蓋前面的。
PS:
1. RHS查詢在所有嵌套的範圍中遍尋不到所需遍曆會拋出ReferenceError。
2. RHS查詢到一個變數,但你嘗試對其不合理的操作(引用null或undefined類型中的屬性),會拋出TypeError。