關於setTimeout()與for(){}迴圈之間的糾纏不清
阿新 • • 發佈:2020-08-24
問題寫法
for(var i = 1; i <= 5; i++) {
setTimeout( function(){
console.log(i);
},i*1000);
}
console.log(i);
// 先輸出環境執行產生的一個6,每隔1s,再輸出一個6,連續輸出5個6
- 解析:
- 此處的i是由var定義在全域性作用域內,輸出值i屬於全域性作用域的值
- setTimeout()函式執行機制是,等全域性環境執行完成後,再執行回撥函式
- 因此,i的終值是都是全域性變數i的值
- 因為回撥函式並不是隨著環境一起執行的,而是等到環境函式執行完成後再集中執行的
- 因此,五次迴圈相當於一起執行五次setTimeout()函式
- 所以累加的秒數就相當於,每隔一秒執行一次
let定義寫法
for(let i = 1; i <= 5; i++) {
setTimeout( function(){
console.log(i);
},i*1000);
}
console.log(i);
// 先輸出i未定義,再每隔1s輸出累加值
- 解析:
- 此處的i是由let定義在塊級作用域內,輸出值i屬於塊級作用域的值
- 因此當i值出現變化時,是屬於內部作用域的變化
- 而setTimeout()函式執行機制是,等環境執行完成後,再執行回撥函式
- 因此,當i值出現變化時,已經沒有環境程式在運行了
- 所以,此時for迴圈是跟著setTimeout()函式執行的
- 因此,i的輸出值是for迴圈的累加值
立即函式寫法
for(var i = 1; i <= 5; i++) {
(function(i){
setTimeout( function(){
console.log(i);
},i*1000);
})(i);
}
console.log(i);
// 先輸出i未定義,再每隔1s輸出累加值
- 解析:
- 此處的i是由var定義在全域性作用域內,輸出值i屬於全域性作用域的值
- 雖然,setTimeout()函式執行機制是,等全域性環境執行完成後,再執行回撥函式
- 但是,每次的for迴圈執行時,內部的立即函式都會執行
- 而且,i的值會由形參i傳入到setTimeout()函式內部
- 從而形成關於i的私有作用域
- 因此此時的setTimeout()函式是和環境程式一起行動的
- 而最外圍的i的輸出沒有時延,因此會先輸出
閉包函式寫法
for (var i = 1; i <= 5; i++) {
setTimeout(function(i) {
return function(){
console.log(i);
}
}(i), i*1000);
}
console.log(i);
// 先輸出i未定義,再每隔1s輸出累加值
- 解析:
- 此處的i是由var定義在全域性作用域內,輸出值i屬於全域性作用域的值
- setTimeout()函式執行機制是,等全域性環境執行完成後,再執行回撥函式
- 而此處的閉包寫法,已然將for迴圈中i的變數值通過形參i保存於return機制中
- 形成私有作用域
- 待setTimeout()進行回撥函式執行時,i將輸出私域內的累加值
錯誤寫法
for(var i = 1; i <= 5; i++) {
setTimeout(function(i){
console.log(i);
}(i),i*1000);
}
console.log(i);
- 解析:
- 此處的setTimeout()函式內的回撥函式
- 在主程式執行時,已經隨著主程式一起執行完畢
- 待setTimeout()非同步執行時,已無回撥函式可用