函数无法正常使用外部循环的变量值
当我们在for循环中用了一个setTimeout函数,会发现每次函数在用外部循环的变量会有问题,js代码如下:
初始代码:
<script>
var arr=[1,2,3]
for (var i = 0; i <arr.length; i++) {
setTimeout(function(){
console.log(arr[i])
})
}
</script>
初始代码输出:
我们在控制台输出结果为:
初始代码整理:
出现这个问题是因为for循环是一个同步任务,而setTimeout为一个异步函数,在代码执行时,for循环会先执行直到条件不满足,然后才执行setTimeout里面的 异步任务。我们将代码整理一下,其实它是这样的:
<script>
var arr=[1,2,3];
var i;
i=0;
i=1;
i=2;
i=3;
setTimeout(function () {
console.log(arr[i])
})
setTimeout(function () {
console.log(arr[i])
})
setTimeout(function () {
console.log(arr[i])
})
</script>
当for循环结束时变量i的值为3,最后控制台输出了3次arr[3],即输出3次undefind,解决办法:
方法一:使用自调用函数
方法一代码:
<script>
var arr = [1, 2, 3]
for (var i = 0; i < arr.length; i++) {
(function(i){
setTimeout(function () {
console.log(arr[i])
})
}(i))
}
</script>
方法一代码输出:
方法一代码整理:
问题解决,因为当我们使用一个函数将异步函数包起来并传入参数时,相当于每次都在函数里面重新定义了一个变量并赋值,整理代码如下:
<script>
var arr=[1,2,3];
var i;
i=0;
i=1;
i=2;
i=3;
(function(i){
vari;
i=0;
setTimeout(function () {
console.log(arr[i])
})
}(i))
(function(i){
vari;
i=1;
setTimeout(function () {
console.log(arr[i])
})
}(i))
(function(i){
vari;
i=2;
setTimeout(function () {
console.log(arr[i])
})
}(i))
</script>
方法二:使用let定义循环变量
方法二代码:
<script>
var arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {
setTimeout(function () {
console.log(arr[i])
})
}
</script>
输出结果与自调用函数一样;因为我们定义变量时将var换成let就限定了变量的作用域,代码执行过程与自调用函数类似,也是最简便的方法。
方法三:使用index记录下标
方法三代码:
<script>
var arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {
arr[i].index=i;
setTimeout(function () {
console.log(arr[i])
})
}
</script>
此时控制台输出同样为1,2,3
总结:
其实出现这个问题的关键在于使用var定义变量会有一个变量提升的过程,使之成为了全局变量,我们就想办法限定变量的作用域,把它变成一个局部变量来使用。