var arr = [
{time:2000, description:"123"},
{time:5000, description:"456"},
{time:8000, description:"789"},
];for(var i=0; i<arr.length; i++){
setTimeout( function(){
alert(arr[i].description);
}, arr[i].time );
}我可以理解为,当i=3的时候,匿名闭包早已经访问了arr数组,arr没有i=3的,所以报错arr[i] is undefined但采用函数工厂模式,为其创造一个新的上下文环境就正常for(var i=0; i<arr.length; i++){
setTimeout( function(a){
return function(){
alert(arr[i].description);
}
}(i), arr[i].time );
}如何解释清楚这个情况?
{time:2000, description:"123"},
{time:5000, description:"456"},
{time:8000, description:"789"},
];for(var i=0; i<arr.length; i++){
setTimeout( function(){
alert(arr[i].description);
}, arr[i].time );
}我可以理解为,当i=3的时候,匿名闭包早已经访问了arr数组,arr没有i=3的,所以报错arr[i] is undefined但采用函数工厂模式,为其创造一个新的上下文环境就正常for(var i=0; i<arr.length; i++){
setTimeout( function(a){
return function(){
alert(arr[i].description);
}
}(i), arr[i].time );
}如何解释清楚这个情况?
alert(arr[i].description);
}, arr[i].time );红色部门可以看作是一个事件处理函数,类似与ajax回调函数,所以他不是立即执行
而当他执行时,循环以结束
return function(){
alert(arr[i].description);
}
}(i), arr[i].time );函数执行会产生一个作用域,与外部无关,局部变量可在里面保存。 i为函数参数被传入,所以自然在里面保存
因为for循环跑的快,在第三次运行setTimeout之前i已经变化了for循环是阻止了,但是i++没有阻止
var arr = [
{time:2000, description:"123"},
{time:5000, description:"456"},
{time:8000, description:"789"},
];for(var i=0; i<arr.length; i++){
setTimeout( function(){
alert(i+' '+(arr[i]&&arr[i].description));
}, arr[i].time );
}
/**
* i=0:在两秒后执行alert(i+' '+(arr[i]&&arr[i].description))
* i=1:在五秒后执行alert(i+' '+(arr[i]&&arr[i].description))
* i=2:在八秒后执行alert(i+' '+(arr[i]&&arr[i].description)) * 每次执行setTimeout语句后i都递增,在i=2时执行了setTimeout语句后i=3
* 就像5楼和2楼说的一样:
* 1.在for语句块内,姑且把i变量的作用域看成for块。
* 2.for执行的很快,当执行第一个alert时for已经遍历完毕,且i=3(执行setTimeout语句后i递增)
*/
for(var i=0; i<arr.length; i++){
setTimeout( function(a){
return function(){
alert(i+' '+(arr[i]&&arr[i].description));
}
}(i), arr[i].time );
}
/**
* 这种情况和第一种类似,主要原因是变量i的作用域依然是for块,
* 即使是return返回的函数中的变量i,它的作用域依然是for块,
* 加入你把return返回的函数改变一下,改为:function(){
alert(a+' '+(arr[a]&&arr[a].description));
}
* 即:
*/
var arr = [
{time:2000, description:"123"},
{time:5000, description:"456"},
{time:8000, description:"789"},
];for(var i=0; i<arr.length; i++){
setTimeout( function(a){
return function(){alert(a+' '+(arr[a]&&arr[a].description));}
}(i), arr[i].time );
}
/**
* 这时i的作用域姑且看成for块,而return返回的函数中的变量a(参数),它的作用域应该是setTimeout执行时的环境。
* 变量由参数传递进去,这时在i=2时执行了setTimeout语句(执行完后i也递增了),传递进去后a为2,执行完setTimeout后i为3,检测i<arr.length,不成立,不再执行setTimeout语句,而此时setTimeout执行环境中用的变量是参数a=2,不在是for中的i=3,所以这个就正确、不出错
*/
你google下settimeout就会明白为什么会出错了,因为这些函数执行的时候,i的值为4
setTimeout(function(){
alert(i);
}, 1);
}
for(var i = 0; i < 3; i++){
setTimeout(function(){
alert(i);
}, 0);
}
嗯 你的问题我会keep住,仔细研究下
PS:一般处理这种错误我经常用的是函数委托。
我换种等价写法,马上就明白了,不过是js里面for语句没有自己的作用域罢了
var i;
for(i=0; i<arr.length; i++){
setTimeout( function(){
alert(arr[i].description);
}, arr[i].time );
}
一下就清楚了撒,setTimeout时间到时,for循环已经执行完了,i=3;所以超出了索引
这个写法和原写法是等价的,可以自己测试
for(var i=0; i<3; i++){
var test="test";
}
alert(i);//这儿会弹出3而不是undefind,说明i的作用域不是在for语句内
alert(test);//这个也不会弹出undefind,因为test的作用域也不是for语句,for语句没有单独作用域