先看一段代碼
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, i * 1000);
}
輸出結果是什麼?? 肯定有好多人以為是 0 1 2 3 4
這麼想當然是錯的,因為setTimeout()執行的是一個異步的操作,那能異步到什麼地步呢,就是當所有的代碼執行完畢之後,才會執行setTimeout() 是以當setTimeout函數執行的時候for循環早就已經執行完畢了,那麼此時的i值就是5 是以正确的結果就是 5 5 5 5 5
- 現在來思考一個問題,假如說我就是想用這種方式來實作輸出0 1 2 3 4呢??有可能嗎?怎麼實作呢?
- 不賣關子了,明确的說使用閉包的原理可以解決這個問題。
閉包在JS中被稱為神話一樣的存在
- 要想形成閉包一個必要的條件,你得有一個父級的函數,包包覆延時器,當延時器在被調用的時候,延時器與foo内部的上下文形成閉包,類似于下面這樣
for (var i = 0; i < 5; i++) {
function foo() { //父級函數
setTimeout(() => {
console.log(i);
}, i * 1000);
}
foo()
}
- 如上父級函數foo包包覆了延時器setTimeout,但是現在我們運作仿佛結果還是 5 5 5 5 5 怎麼回事哪裡出錯了嗎???
- 究其原因原來是因為,setTimeout在調用的時候雖然與foo()的内部形成了閉包,但是我們并沒有把i的值給限定在每一個閉包裡面,于是改成下面的代碼就可以如願以償了
for (var i = 0; i < 5; i++) {
function foo(i) { //父級函數
setTimeout(() => {
console.log(i);
}, i * 1000);
}
foo(i)
}