解讀經典面試題for循環console.log


for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i)
},1000)
}


會打印出5個6,這是why

因為 for 循環會先執行完(同步優先於異步優先於回調),這時五個 setTimeout 的回調全部塞入了事件隊列中,然后 1 秒后一起執行了。
為什么不是 1 2 3 4 5 ,問題出在作用域上。

為 setTimeout 的 console.log(i); 的i是 var 定義的,所以是函數級的作用域,不屬於 for 循環體,屬於 global。
等到 for 循環結束,i 已經等於 5 了,這個時候再執行 setTimeout 的五個回調函數(參考上面對事件機制的闡述),里面的 console.log(i);
的 i 去向上找作用域,只能找到 global下 的 i,即 5。所以輸出都是 5。

辦法1:人為給 console.log(i); 創造作用域,保存i的值。
for (var i = 0; i < 5; i++) {
   ( function (i){   //立刻執行函數
     setTimeout( function (){
       console.log(i);
      },1000);
   })(i);
}
這里用到立刻執行函數。這樣 console.log(i); 中的i就保存在每一次循環生成的立刻執行函數中的作用域里了。
 
辦法2
for (let i = 0; i < 5; i++) {   //let 代替 var
   setTimeout( function (){
     console.log(i);
    },1000);
}
let 為代碼塊的作用域,所以每一次 for 循環,console.log(i); 都引用到 for 代碼塊作用域下的i,因為這樣被引用,所以 for 循環結束后,這些作用域在 setTimeout 未執行前都不會被釋放。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM