JS关于setTimeout()与for(){}循环之间的纠缠不清

问题写法

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()异步运行时,已无回调函数可用
原文地址:https://www.cnblogs.com/SharkJiao/p/13552430.html