昨天總結了一些作用域的學問【前端工程師手冊】JavaScript之作用域,然則宣布完發明忘記了一些東西,本日拾個遺。
昨天說到了JavaScript中沒有塊級作用域,其實在es6中是有的。
es6中的塊級作用域
先舉個栗子:
var foo = true;
if (foo) {
let bar = foo * 2;
bar = something( bar );
console.log(bar);
}
console.log( bar ); // ReferenceError
這個是let最直觀的作用,在一對大括號中創建了塊級作用域,bar會在大括號中的代碼實行終了后燒毀。
再舉個栗子:
for(var i = 1;i <= 5;i++) {
setTimeout(function() {
console.log(i)
}, i*1000)
}
// 每隔一秒打印一個6,共打印5次
如果說這段代碼的初志是距離1秒打印出1、2、3、4、5的話,結果是使人大跌眼鏡的,真正的結果是每隔1秒打印一次6,打印5次.
為何會這模樣?起首是因為閉包的緣由,閉包背面再說,現在先理解為閉包是一個函數,一個可以接見並未在它自己內部定義的變量的函數。
OK,接下來講深層次緣由。for輪迴終了以後,i=6,且此時生成了5個匿名函數 function(){ console.log(i) },因為這5個匿名函數處在同一個詞法作用域中,所以他們援用同一個i,所以當他們實行時,天然而然就會打出6。
怎樣處理?
for(let i = 1;i <= 5;i++) {
setTimeout(function() {
console.log(i)
}, i*1000)
}
// 距離一秒離別打印出1、2、3、4、5
把var換成let聲明就可以了。
《你不知道的JavaScript-上卷》中解釋道:
for 輪迴頭部的 let 不僅將 i 綁定到了 for 輪迴的塊中,事實上它將其從新綁定到了輪迴的
每個迭代中,確保運用上一個輪迴迭代完畢時的值從新舉行賦值。
說白了就是再每次迭代內部,都會對 i 舉行隱形的從新賦值,且運用的是上一個迭代完畢時的值來對 i 舉行從新賦值。
差不多就是如許的:
for(let i = 1;i <= 5;i++) {
let i = 上次迭代完畢的i
setTimeout(function() {
console.log(i)
}, i*1000)
}
所以5個匿名函數援用的並非同一個i,天然就會順遂的距離一秒離別打印出1、2、3、4、5了