循环中的闭包
2015-06-01 05:18
441 查看
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
不过这段代码执行的结果是10,而不是0,1,2,3,4,5,6,7,8,9。
为什么呢?
(引自:http://www.douban.com/note/293295975/)
因为setTimeout是异步的!
你可以想象由于setTimeout是异步的, 因此我们将这个for循环拆成2个部分
第一个部分专门处理 i 值的变化, 第二个部分专门来做setTimeout
因此我们可以得到如下代码
// 第一个部分
i++;
...
i++; // 总共做10次
// 第二个部分
setTimeout(function() {
console.log(i);
}, 1000);
...
setTimeout(function() {
console.log(i);
}, 1000); // 总共做10次
这样一拆后, 我相信你肯定知道之前那个for循环的运行结果了.
由于循环中的变量 i 一直在变, 最终会变成10, 而循环每每执行setTimeout时, 其中的方法还没有真正运行, 等真正到时间执行时, i 的值已经变成 10 了!
i 变化的整个过程是瞬间完成的, 总之比你异步要快, 就算你setTimout是0毫秒也一样, 会先于你执行完成.
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
避免引用错误
为了正确的获得循环序号,最好使用 匿名包裹器(译者注:其实就是我们通常说的自执行匿名函数)。for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); }
外部的匿名函数会立即执行,并把
i作为它的参数,此时函数内
e变量就拥有了
i的一个拷贝。
当传递给
setTimeout的匿名函数执行时,它就拥有了对
e的引用,而这个值是不会被循环改变的。
有另一个方法完成同样的工作;那就是从匿名包装器中返回一个函数。这和上面的代码效果一样。
for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) }
以上引自(密码花园:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.closures)
上面的代码看起来都比较费劲,下面我把代码拆分开,更容易理解一些。
window.onload= function(){
for(var i=0; i<5; i++){
/*(function(j){
setTimeout(function(){ //setTimeout是在循环结束后才被“异步”调用的
console.log(j+'');
},100);
})(i);*/
test(i);
}
}
function test(j){
setTimeout(function(){
console.log(j+'');
},100);
}
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- 深入理解PHP之匿名函数
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 异步流程控制:7 行代码学会 co 模块
- JavaScript拆分字符串时产生空字符的原因
- IE8开发人员工具教程(二)
- 在flex中执行一个javascript方法的简单方式
- Flex结合JavaScript读取本地路径的方法
- ruby实现的一个异步文件下载HttpServer实例
- Ruby中使用Block、Proc、lambda实现闭包
- PowerShell中执行Javascript的方法示例
- javascript asp教程第六课-- response方法
- javascript asp教程More About Recordsets
- javascript asp教程第十二课---session对象