a = 2;
var a;
console.log(a); // 2
複製代碼
console.log(a); // undefined
var a;
複製代碼
變量和函數在內的全部聲明都會在任何代碼被執行前首先被處理。bash
JavaScript會將var a = 2;當作兩個聲明: var a; 和 a = 2;第一個定義聲明是在編譯階段進行的。第二個賦值聲明會被留在原地執行階段。函數
因此上面的兩個代碼片斷會以以下形式進行處理:spa
var a;
a = 2;
console.log(a);
複製代碼
var a;
console.log(a);
複製代碼
這個過程就好像變量和函數聲明從它們在代碼中出現的位置被「移動」到了最上面。 這個過程就叫作提高。code
foo();
function foo(){
console.log(a); // undefined
var a = 2;
}
複製代碼
foo函數的聲明(這個例子還包括實際函數的隱含值)被提高了,所以第一行中的調用能夠正常執行。ip
每一個做用域都會進行提高操做。作用域
上面的代碼實際上會被理解爲下面的形式:string
function foo(){
var a;
console.log(a); // undefined
a = 2;
}
foo();
複製代碼
函數聲明會被提高,可是函數表達式卻不會被提高。it
foo(); // 不是ReferenceError,而是TypeError!
var foo = function bar(){
// ...
}
複製代碼
這段程序中的變量標識符foo被提高並分配給所在做用域,所以foo不會致使ReferenceError。可是foo此時並無賦值,foo()因爲對undefined值進行函數調用而致使非法操做,所以拋出TypeError異常。io
即便是具名的函數表達式,名稱標識符在賦值以前也沒法在所在做用域中使用。console
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar(){
// ...
}
複製代碼
上面的代碼片斷通過提高後,實際上會被理解爲如下形式:
var foo;
foo(); // TypeError
bar(); // ReferenceErro
foo = function(){
var bar = ...self...
// ...
}
複製代碼
函數聲明和變量聲明都會被提高。可是有一個細節是,函數首先被提高,而後纔是變量。
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儘管出如今function foo()...的聲明以前,但它是重複的聲明(所以被忽略了),由於函數聲明會被提高到普通變量以前。
儘管重複的var聲明會被忽略掉,但出如今後面的函數聲明仍是能夠覆蓋前面的。
foo(); //3
function foo(){
console.log(1)
}
var foo = function(){
console.log(2)
}
function foo(){
console.log(3)
}
複製代碼
全部的聲明(變量和函數)都會被「移動」到各自做用域的最頂端,這個過程被稱爲提高。
關於溝通
我買了一本《溝通的技術》,並無耐心看幾頁,一直在牀頭落灰,可能這是個人溝通能力一直沒有獲得提高的緣由。因此要在這裏立個flag,每週看一章,不能再少了,否則就接不上上下文了。