4.1 變量提升
console.log(a);//<--理解爲什麼是undefined而不是2,也不是ReferenceError異常。
var a=2;
引擎會在解釋JavaScript代碼之前首先對其進行編譯,編譯階段中的一部分工作就是找到所有的聲明,並用合適的作用域將它們關聯起來。
包括變量和函數在內的所有聲明都會在任何代碼被執行前首先被處理。
例如 var a = 2;JavaScript在處理時會當做兩個聲明來處理
- var a; 在編譯階段進行;
- a = 2;在原地等待執行階段;
值得注意的是,函數聲明會被提升,但是函數表達式不會。
foo();//不是ReferenceError,而是TypeError
bar();//ReferenceError
var foo = function bar(){
//...
}
由於foo是一個函數表達式,而不是一個函數聲明(不以function開頭作爲第一個詞),所以提升時並沒有賦值,以上代碼可以理解爲:
var foo;
foo(); //TypeError
bar(); //ReferenceError
foo = function() {
var bar = ..self..
//...
}
4.2 函數優先
函數聲明和變量聲明都會提升,但是函數首先被提升,然後纔是變量,函數聲明會被提升到普通變量之前。
儘管重複的var聲明會被忽略,但是出現在後面的函數聲明還是可以覆蓋掉前面的。
foo(); //3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
}
function foo() {
console.log(3);
}
4.3 小結
var a = 2; 對於JavaScript引擎來說是兩個單獨的聲明,第一個是編譯階段的任務,第二個則是執行階段的任務。
這意味着無論作用域的聲明出現在什麼地方,都將在代碼本身被執行前首先進行處理。可以將這個過程形象的想象成所有的聲明(變量和函數)都會被“移動到”各自作用域的最頂端,這個過程被稱爲提升。
聲明本身會被提升,而包括函數表達式的賦值在內的賦值操作並不會提升。
要注意避免重複聲明,特別是當普通的var聲明和函數聲明混在一起的時候,否則會引起很多危險的問題!