在此之前,希望我们已经了解了作用域链的概念。
首先我们来看一个问题:
function text() {
var arr=[];
for (var i=0;i<10;i++) {
arr[i]=function () {
document.write(i+" ");
}
}
return arr;
}
var a=text();
for (var i=0;i<a.length;i++) {
a[i]();
}
打印什么结果?
很简单咯,0 1 2 .... 9咯 哈哈
现实是这样的:
我艹,。
为什么会这样了?
我们先来看一个简单的例子:
function a() {
function b() {
var bbb = 234;
document.write(aaa);
}
var aaa=123;
return b;
}
var glob=100;
var demo=a();
demo();
打印结果是123.
我们从底层来理解一下这个问题。
代码先预编译,一开始遇到了a函数的声明,和glob变量.
到var demo=a()时,执行a函数,此时a函数的作用域链:
这个首先得先明白!然后开始b函数的定义,此时b函数的作用域链将直接用它爸爸(a)的作用域链,那么此时变成:
b函数比较厚脸皮直接就用a的了,注意这里它们指向的都是同一个地方!!!
然后a函数结束了,然后a函数恢复到它定义的时候,然后它的AO就没有了(注意我这里其实用词不准,希望引起注意),其实AO并没有消失,它还在,但是a函数的作用域链已经不”指向“它了。此时变成了这样:
b函数在a函数结束前被丢出来了,被赋给demo了,然后执行demo();生成了自己的作用域链AO,然后b函数根据自己的作用域链来执行代码(找变量aaa) 自己的AO没有,就找a的作用域链,然后找到了,输出123.
我们现在应该明白,销毁什么函数,变量,其实没有销毁,只是没有指向它的地址了,它还在内存中保存着。(题外话:自己的硬盘的,电脑,存储信息的东西不要随便丢掉!"心怀鬼胎"的人可以通过一些手段,完全可以弄出来的。有没有删掉的照片有一天自己又冒出来的经历。
闭包就是这样形成的,一个函数的内部有另外一个函数,内部函数通过外部函数的return 返回到外部形成了闭包,享受外部函数的资源(作用域链)
一开始的问题:
function text() {
var arr=[];
for (var i=0;i<10;i++) {
arr[i]=function () {
document.write(i+" ");
}
}
return arr;
}
var a=text();
for (var i=0;i<a.length;i++) {
a[i]();
}
为什么会是10个10了,现在应该明白了,因为10个arr[]函数与一个text变量形成了一个闭包(1对10)
它们公用了一个变量i,而text函数结束时i变量是10。
闭包的解决方案:
我们首先了解立即执行函数点击打开链接
我们就要输出0 1 2 .... 9怎么办
上面输出10个10的原因俩个:
1:形成了1对10的闭包
2:公用了变量i
我们先看一下这段代码:
function text() {
var arr=[];
for (var i=0;i<10;i++) {
(function(j) {
arr[j]=function (){
document.write(j+" ");
}
}(i))
}
return arr;
}
var a=text();
for (var i=0;i<a.length;i++) {
a[i]();
}
这段代码就解决了,怎么解决的了?
1:我们生成了10个函数(虽然是立即执行函数,但还是10个)10对10
2:虽然是立即执行函数,但是它的作用域链没有消失咯,被相应的arr保存了,执行的时候就找到j了,而j并不是共享的。
立即执行函数用于解决闭包问题非常方便,基本上就是此方法了。