今天做一个循环想得到1,2,3...10的输出结果。自己写的放弃了,然后看到了这么一个方案,但不是很理解,不知道自己哪一方面知识的欠缺,求大神解答!!!
var funcs = [];
for (var i=0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
funcs.forEach(function(func) {
func(); // outputs 0, then 1, then 2, up to 9
});
自己访问自己的变量i,在每一个循环中都传入一个i值???
知识点:
词法作用域
闭包
立即执行函数表达式
一步一步来,首先,你写的应该是这样:
分析:9从哪里来?9为循环i的最终值。函数在循环结束后才调用,所以每次都是9;
但不符合你的目的(从1,2,3 ... 9)依次打印出来,问题出在它们被封闭在一个共享的全局作用域中,实际上就只有一个i,所以都是9。
还是不明白?看这里:假设循环在全局环境中,那么循环中的i(var i=0)便会被提到最上头,相对于循环中的函数, i 便是自由变量(存放在作用域链的[[Scope]]属性中),而循环中的函数都处在同一个父上下文中,它们指向了同一个[[Scope]]属性,所以 i 为同一个。。
思考:那我们给创建各自的作用域不就行了,这样就引入了立即执行函数表达式(题中为匿名函数表达式)来创建各自的作用域。所以改进代码为:
but,结果还是一样都是9,why?因为我们创建了空白的作用域,我们要传入东西才行啊,so:
这样就将 i 传进去了,就是这么任性。。。
补充1:ES6已经有let可以创建块作用域了,所以,上面可以这么写:
建议你看看刚出不久的《你不知道的JavaScript上卷》,这部分讲得很透彻~
补充2:看完3楼,发现漏了i++。。i为10