一、ES5
在循环过程中,如下代码段不能按照编写的本意输出结果(本意是想输出6)。
var arr = [];
for(var i=0; i<10; i++){
arr[i] = function(){
console.log(i);
}
}
arr[6](); //10
由于作用域链的配置机制,导致它们arr[i]引用的都是同一变量i。当循环结束后它们都指向循环最后的结果(i=10),所以arr中每一个的值都是10.
为了能让程序输出想要的值,可以通过创建一个匿名函数强制让闭包的行为符合预期
var arr = [];
for(var i=0; i<10; i++){
arr[i] = function(num){
console.log(num)
}(i);
}
//0
//1
...
//9
上面的代码会依次打印出0~9;由此我们编写如下代码:
var arr = [];
for(var i=0; i<10; i++){
arr[i] = function(num){
return function(){
console.log(num);
}
}(i);
}
arr[6](); //6
在上面的程序中,没有直接将闭包赋值给arr[i]
,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给数组;此时再调用arr[6]();
就能得到想要的结果了。
接下来看看在ES6中会有写什么样的惊喜。
二、ES6
ES6中新增了let
命令,用于声明变量。所声明的变量只在let
命令所在的代码块内有效。所以如要在循环中取特定的值可以用以下代码轻松解决。
var arr = [];
for(let i=0; i<10; i++){
arr[i] = function(){
console.log(i);
}
}
arr[6](); //6
这段代码和最上面第一段只有一个地方不同,就是在for
循环里用let
声明的变量而不是var
。奇迹就这样产生了。由于变量i
是let
声明的,所以当前的i
只在本轮循环中有效。所以每一次循环i
都是一个新的变量,于是最后调用arr[6]()
输出的是6.