for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i)
},0)
}
//結果是輸出10次10;
一:執行機制,同步先執行-異步-最后回調再執行
for循環是同步代碼,而setTimeout中的是異步代碼。
JS中既有同步又有異步的情況下,先從上到下執行同步代碼,碰到異步的代碼會將其插入到任務隊列當中等待。
而setTimeout是延時,也就是說碰到setTimeout這個異步的代碼塊會根據它里面的第二個參數:延時時間來將代碼插入到任務隊列當中。
比如上面這段代碼中,第二個參數延時時間是0,也就是說執行到它的時候會在0ms之后將它插入到任務隊列當中。同步代碼都執行完成之后,那么JS引擎就空閑了,這個時候就輪到任務隊列中的異步代碼依次加載了。
二:作用域鏈
執行settimeout時輸出i,現在當前執行函數中查找i,查找失敗,找到全局作用域i,此時for循環已經執行完畢i=10;
解決辦法-----------------------------立即執行函數,返回當前i
for(var i=0;i<10;i++){
function(a){
setTimeout(function(){
console.log(i)
},0)}(i)
}
輸出0 1 2 3 4 5 6 7 8 9
解決辦法-----------------------------let塊
for(let i=0;i<10;i++){
setTimeout(function(){
console.log(i)
},0)
}
let i 的是區塊變量,每個i只能存活到大括號結束,並不會把后面的for循環的 i 值賦給前面的setTimeout中的i;
i被綁定到循環體的每一次迭代中,確保上一次迭代結束的值重新被賦值。
setTimeout里面的function()屬於一個新的域,
通過 var 定義的變量是無法傳入到這個函數執行域中的,
通過 let 來聲明塊變量,這時候變量就能作用於這個塊,所以 function就能使用 i 這個變量了;
var i 則是局部變量,這個 i 的生命周期不受for循環的大括號限制;