let foo = function(){
console.log(1)
}
(function foo(){
foo = 10;
console.log(foo);
}());
console.log(foo); 複製程式碼
不知道你第一次想到的答案對不對呢?
輸出結果為:
f foo(){
foo = 10;
console.log(foo);
}
1
undefined複製程式碼
我們從後往前說這樣可能更好理解一點
首先undefined對應的是console.log(foo);
之所以是undefined是因為下圖所示位置
沒有分號導致後邊的()把前邊的匿名函式執行了,而如果函式沒有返回值的話,預設返回undefined,然後undefined被賦給了let宣告的變數foo,基於此,也就理解了為什麼1會被列印出來。
接下來就講到了重頭戲,也就是自執行函式中的console.log(foo)為什麼列印出來是函式體而不是10呢?
而在講解這一部分之前,我們先看這樣一段程式碼:
let myBar = function bar(){
bar = 20;
console.log('bar',bar);
console.log('myBar',myBar);
}
myBar();
console.log(myBar);
console.log(bar);
複製程式碼
猜猜這段程式碼會輸出什麼呢?結果如下:
bar ƒ bar(){
bar = 20;
console.log('bar',bar);
console.log('myBar',myBar);
}
myBar ƒ bar(){
bar = 20;
console.log('bar',bar);
console.log('myBar',myBar);
}
ƒ bar(){
bar = 20;
console.log('bar',bar);
console.log('myBar',myBar);
}
Uncaught ReferenceError: bar is not defined
複製程式碼
不難看出,bar內部可以訪問到bar和myBar,但是外面是訪問不到bar的,而且bar內部對bar的重新賦值也是沒有生效的。
由此我們得到結論,函式表示式宣告的函式,函式外部是無法訪問的,而在函式內部是隻讀的,在非嚴格模式下,函式內部的賦值靜默失敗,而在嚴格模式下會報錯
Uncaught TypeError: Assignment to Constant variable複製程式碼
接下來我們再延伸一下,請看如下程式碼:
let foo = function(){console.log(1)}
(function(){
foo = 10;
console.log(foo);
}());
複製程式碼
這段程式碼執行會輸出什麼呢?結果報錯如下:
Uncaught ReferenceError: foo is not defined
複製程式碼
有疑問的朋友可能會問,怎麼是not defined呢,明明我在自執行函式裡邊有宣告啊?
這是因為用let宣告的變數,不存在變數提升。而且要求必須 等let宣告語句執行完之後,變數才能使用,不然會報Uncaught ReferenceError錯誤。
ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。總之,在程式碼塊內,使用let命令宣告變數之前,該變數都是不可用的。這在語法上,稱為“暫時性死區”(temporal dead zone,簡稱 TDZ)。作為引數的自執行函式先執行,而此時foo處於暫時性死區,所以報錯了。
如果有錯誤或者不嚴謹的地方,請給予指正,十分感謝!