JS高程中关于闭包与变量这一节,讲到一个案例,我当时看的一脸懵逼,然后就自习的研究了一下,先上代码:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
//调用最外层函数,接收返回的数组
var arr = createFunctions();
// 循环遍历数组,调用每个元素并打印
for (var i = 0; i < arr.length; i++ ) {
console.log(arr[i]()); //10
}
为啥是10个10呢,乍一看,循环的时候,返回的i应该是对应的索引啊,那么打印出来的应该是0-9才对,也就是这样:
result[0] = function() { return 0; };
result[1] = function() { return 1; };
result[2] = function() { return 2; };
其实这个问题的关键在于,函数是啥时候被调用的
在调用createFunctions这个函数之后,返回的result数组实际上是这样的:
result[0] = function() { return i; };
result[1] = function() { return i; };
result[2] = function() { return i; };
而当我们去调用数组中的元素时,数组元素对应的匿名函数才会被调用,此时返回i,很显然,当前作用域中并没有i,那么就需要到他的上一层作用域去找,而这个时候,循环结束, i已经是10了,所以我们无论调用数组中的哪个元素,返回的都是10;
问题的关键就在于,我们没有立即使用i这个变量,而是把它保存在起来,需要的时候再调用,而i这个变量一直在变化,所以我们需要在循环的每一步中,实时地获取i的值,解决方案如下:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
// 给result[i]一个自调用函数,并实时地将i作为参数传递给变量num
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
函数createFunctions被调用之后,在for循环中,自调用函数立即执行,获取实时地i赋值给num. 循环结束之后,返回result:
result[0] = function() { return num;};
result[1] = function() { return num;};
result[2] = function() { return num;};
此时我们再调用数组元素时,闭包函数会去他的上层作用域中寻找num的值,(虽然用i给num赋值的自调用函数在被调用之后,它的执行环境的作用域链就被销毁了,但是它的活动对象还在闭包函数的作用域链中,)所以会返回对应的元素下标.
也是参考一些大佬的经验才稍微理解了一些,不足的地方欢迎指正,此贴主要是用来记录总结学习过程中的问题.