提升
a = 2;
var a;
console.log( a );
相當(dāng)于
var a;
a = 2;
console.log( a );//2
console.log( a );
var a = 2;
相當(dāng)于
var a;
console.log( a );
a = 2;
這個過程就好像變量和函數(shù)聲明從它們在代碼中出現(xiàn)的位置被“移動”到了最上面。這個過程就叫做提升。
只有聲明本身會被提升,而賦值或其他運行邏輯會留在原地。如果提升改變了代碼執(zhí)行的順序,會造成非常嚴重的破壞。
函數(shù)聲明會被提升,但是函數(shù)表達式卻不會被提升。如:
foo();// 不是ReferenceError, 而是TypeError!
var foo=function bar() {
console.log(a); // undefined
var a = 2;
}
以上程序中的變量標識符foo()被提升并分配給所在作用域(在這里是全局作用域),因此foo()不會導(dǎo)致ReferenceError。但是foo此時并沒有賦值(如果它是一個函數(shù)聲明而不是函數(shù)表達式,那么就會賦值)。foo()由于對undefined值進行函數(shù)調(diào)用而導(dǎo)致非法操作,因此拋出TypeError異常。
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {
// ...
};
改為:
var foo;
foo(); // TypeError
bar(); // ReferenceError
foo = function() {
var bar = ...self...
// ...
}
函數(shù)優(yōu)先
函數(shù)聲明和變量聲明都會被提升。但是一個值得注意的細節(jié)(這個細節(jié)可以出現(xiàn)在有多個“重復(fù)”聲明的代碼中)是函數(shù)會首先被提升,然后才是變量。
foo(); // 1
var foo;
function foo() {
console.log( 1 );
}
foo = function() {
console.log( 2 );
};
這個代碼片段會被引擎理解為:
function foo() {
console.log( 1 );
}
foo(); // 1
foo = function() {
console.log( 2 );
};
注意,var foo盡管出現(xiàn)在function foo()...的聲明之前,但它是重復(fù)的聲明(因此被忽略了),因為函數(shù)聲明會被提升到普通變量之前。
盡管重復(fù)的var聲明會被忽略掉,但出現(xiàn)在后面的函數(shù)聲明還是可以覆蓋前面的:
foo(); // 3
function foo() {
console.log( 1 );
}
var foo = function() {
console.log( 2 );
};
function foo() {
console.log( 3 );
}

但愿人長久,千里共嬋娟