闭包的特性
视频锁定
{$ currentTime | date:'mm:ss' $}
{$ timeLeft | date:'mm:ss' $}
我们先来看一个例子,如果不了解 JavaScript 的特性,很难找到原因:
var outter = [];
function clouseTest () {
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(){
print(i);
}
outter.push(x);
}
}
//调用这个函数
clouseTest();
print(outter[0].invoke());
print(outter[1].invoke());
print(outter[2].invoke());
print(outter[3].invoke());
运行的结果如何呢?很多初学者可能会得出这样的答案:
0
1
2
3
然而,运行这个程序,得到的结果为:
4
4
4
4
其实,在每次迭代的时候,这样的语句 x.invoke = function(){print(i);}
并没有被执行, 只是构建了一个函数体为print(i);
的函数对象,如此而已。而当 i=4 时,迭代停止,外部函数返回,当再去调用 outter[0].invoke()
时,i 的值依旧为 4,因此 outter 数组中的每一个元素的 invoke 都返回 i 的值:4。
如何解决这一问题呢?我们可以声明一个匿名函数,并立即执行它:
var outter = [];
function clouseTest2(){
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(no){
return function(){
print(no);
}
}(i);
outter.push(x);
}
}
clouseTest2();
这个例子中,我们为 x.invoke
赋值的时候,先运行一个可以返回一个函数的函数,然后立 即执行之,这样,x.invoke
的每一次迭代器时相当与执行这样的语句:
//x == 0
x.invoke = function(){print(0);}
//x == 1
x.invoke = function(){print(1);}
//x == 2
x.invoke = function(){print(2);}
//x == 3
x.invoke = function(){print(3);}
这样就可以得到正确结果了。闭包允许你引用存在于外部函数中的变量。然而,它并不是使用该变量创建时的值,相反,它使用外部函数中该变量最后的值。
在线练习
{$ activeFileHint $}