1. 程式人生 > >javascript 中的立即呼叫函式模式、閉包及es6中的塊級作用域

javascript 中的立即呼叫函式模式、閉包及es6中的塊級作用域

先來看一個在牛客上看到的面試題:

這裡一開始會以為是不就是隔1秒輸出i的值嗎,最後結果就是輸出0~9 的十個數字呀,真的是太young了。

但是真是擼了一遍程式碼,控制檯輸出刺眼的10個10,what?

這個查了資料是說因為這個函式為每一個i都設定了一個計時器,那麼就設定了10個計時器,但是它們被存放在佇列中,for迴圈結束

後setTimeout()函式才得以執行,而這時i的值為10,於是就輸出10個10,如果還是不太明顯,再看以下例子--->

這段程式碼利用var在迴圈中建立了一個函式,然後在迴圈外呼叫函式, 得到的結果卻不是0到9,輸出的是10個10,這是因為每次

迴圈裡的每次迭代同時共享著變數 i ,迴圈內部建立的函式全都保留著對相同變數的引用,迴圈結束變數i的值為10,所以每次呼叫console.log(i) 時輸出的數字為10。

那麼如何輸出0到9呢,從以上兩個例子去修改。方法有兩種,第一種是使用閉包(有時會結合IIFE模式使用);第二種是使用

ES6的塊級作用域,用let 宣告變數。看看具體實現

這個是使用閉包實現輸出0到10 十個數字, 閉包類似其他類C語言的類和塊的概念類似,這裡通過與理解呼叫函式模式結合,建立後立即呼叫,可以在外部訪問到區域性建立的函式域裡的變數。

這裡使用立即呼叫函式表示式,強制生成計數器變數的副本並儲存為變數value,這個變數的值就是相應迭代建立的函式所使用

的值,因此呼叫每個函式都會像從0到9一樣得到期望值。

塊級作用域----用let關鍵字宣告變數,相對於閉包操作簡單一點:

這裡僅僅是用let 關鍵字代替了 var 就得到想要的結果,輸出0到10 每個數字, var 宣告在函式中會有變數提升,let 宣告則沒有這個變數提升.

let 宣告模仿IIFE模式,每次迭代迴圈都會建立一個新的變數,並以之前迭代中同名變數的值將其初始化。

同樣也可以用const 宣告實現類似的結果。

關於let宣告和const宣告可以多去看看es6的文件。不過這個閉包和立即呼叫模式還有變數提升真的是深坑,不多跳幾次還是不會

長記性的。

-------------寫這篇博文時太陽剛好西斜,晒到我半邊身子,滿滿陽光的味道。怕什麼坑太多,能填一個是一個。