闭包与循环
2017-08-21 本文已影响0人
xiaoguo16
先来一个例子:
function A(){
var m=[];
for(var i=0;i<5;i++){
m[i]=function () {
return i
}
}
return m;
}
var a=A()[0]
a();//5
上面的例子中数组m中保存的函数返回值都为5。
why?
上述例子中的a是匿名函数,而执行匿名函数时,匿名函数保存着外层函数的活动对象的引用,而它们引用的都是外层函数中的i,也就是引用的同一个值,所以都是最后的变量i。
修改后:
function A(){
var m=[];
for(var i=0;i<5;i++){
m[i]=function(j){
return function () {
return j;
}
}(i)
}
return m;
}
var a=A()[0]
a();//0
原理:
利用函数传参的特点,函数传参是按值传递的,而非按引用,所以j中保存的是i的副本,也就是每次的值都是不同的。
常见错误
for(var i=1;i<=5;i++){
setTimeout(function(){
console.log(i);
},i*1000)
}
//输出5个6;
why?
Paste_Image.png先运行主线程序,然后运行到setTimeout这个异步函数时,它会有一个延迟,此时该函数中的function丢入副线运行,主线继续执行,当执行完for循环后,此时在检查副线进程,发现副线已经到时间了,就传给它i值,但此时的i值已经变为6了,所以后面的function都是6。
但是这里即便延迟为0,仍然是输出5个6,因为它们对i的引用为同一个值。
解决方案
for(var i=1;i<=5;i++){
(function(j){
setTimeout(function(){
console.log(j)
},1000)
})(i)
}
//1,2,3,4,5
利用函数的传参的性质,按值传递,所以j是i的副本,即分别为1,2,3,4,5。