Babel的小bug引發的疑問:es6的let類型與閉包間的關係

let是ES6變量類型,其只在代碼塊內有效。

閉包是有函數以及創建該函數的詞法環境組合而成,這個環境包含了這個閉包創建時所能訪問的所有局部變量。

如果合理使用閉包,可以使用var實現let局部有效的效果。顯然這是多餘的,因為babel已經能幫我們做了,並且很多新版瀏覽器都支持let,所有本文結束。

等等,babel都幹了啥?為啥能將let轉碼使代碼兼容舊版瀏覽器?

兼容轉碼

我們先來看一段比較簡單的babel轉碼

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

我們來搬一段特別複雜的let類型申明代碼

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

在babel官網將其轉碼為兼容代碼:

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

老司機馬上就看出了:將let轉為了閉包

閉包

我們來看看MDN上的一段例子

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

閉包是由函數以及創建該函數的詞法環境組合而成。這個環境包含了這個閉包創建時所能訪問的所有局部變量。

我們一通分析便可以看出code3閉包的基本結構:

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

code4的閉包是立即執行

利用閉包,使var == let

code4的結構不正是code2的簡寫嗎?我們可以將code2改寫為

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

說好的簡寫呢?!

仔細閱讀這句話閉包是由函數以及創建該函數的詞法環境組合而成。這個環境包含了這個閉包創建時所能訪問的所有局部變量。

let是塊級作用域,也就是局部作用域。閉包也是能訪問局部作用域。

code4正是將變量i賦值給函數的局部變量j,code5中數組a的每個item都是該函數實例的引用。

在let出現之前,在循環中寫閉包是一個比較常見的問題。

我們不鼓勵在循環中創建閉包,過多的閉包會付出性能代價。

Babel的bug

意外發現了一個Babel的小bug。我們在最新的Chrome/Firefox瀏覽器中運行這段代碼:

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

會發現輸出結果為3次”abc 1539160907***”。將code6通過Babel轉碼得到code7

Babel的小bug引發的疑問:es6的let類型與閉包間的關係

code7在瀏覽器中僅僅運行了1次,輸出結果為”abc 1539160907***”

阮老師講:

for循環還有一個特別之處,就是設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域。


分享到:


相關文章: