第一种情况
for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log('i-'+i);
return function(){
console.log('i-'+i);
}
}(), 2000)
}
执行结果为 i-1,i-2...i-9 。两秒后输出 10 次 i-10
第二种情况 将代码改为如下
for (var i = 0; i < 10; i++) {
setTimeout(function(){
var s = i
console.log('i-'+i);
return function(){
console.log('s-'+s);
}
}(), 2000)
}
执行结果为 i-1,i-2...i-9 。两秒后输出 s-1,s-2...s-9
第三种情况
for (var i = 0; i < 10; i++) {
(function(){
console.log('i-'+i);
return function(){
console.log('s-'+i);
}()
})()
}
执行结果为i-1,s-1...i-9,s-9 这是什么原因呢
1
learnshare 2017-04-18 16:01:30 +08:00
闭包保存了“现场”,也就是当时的状态
|
2
ma199385 OP @learnshare 您在看下我添加的第三种情况
|
5
kutata 2017-04-18 16:38:37 +08:00
其实我觉得这应该是作用域的问题,面非闭包。
第一种情况你把 var 改为 let 就输出就正常了。 具体可以参考以下这篇文章,<块级作用域> 章节。 http://lifemap.in/es2015-in-action/ |
6
jklopsdfw 2017-04-18 16:41:26 +08:00 via Android
@ma199385 第一种情况定时器调用的函数在两秒后只能找到两秒后外层的 i ,第二种情况定时器调用的函数两秒后找到两秒前赋值的 s ,第三种情况没有定时器,啥时候调用就找啥时候的 i
|
7
xss 2017-04-18 16:52:27 +08:00
你的 setTimeout 里面的回调函数, 存在于特定的上下文中.
顺着原型链网上找: 1. 首先 i-1,i-2...i-9 是第一个 console.log 输出的.然后 2 秒之后返回了函数,此时 for 循环已经执行完毕, i 的值在原型连上是 10, 所以再输出 10 次 10. 2. 第一次的输出同 1, 不同的是, 第二次输出的是 s 的值, 而每次原型链上 s 的值是 i 的副本(值传递), 所以第二次会输出 s-(保存的 i 值), s-(保存的 i 值). 但是注意, 实际上保存的 i 值的顺序并不一定是递减或递增的关系, 在极端情况下可能是乱序的. 这个和定时器的精度有关. 3. 函数调用栈问题, 最外侧匿名函数首先被调用, 然后内部的匿名函数再获得调用机会. 每次 for 循环都是如此, 先调用外部的函数, 输出 i-1, 然后内部匿名函数获得调用, 输出 s-1, 其余情况类推. |