首先我们得了解一下什么是闭包? 我们看百度词条是这样解释的 ? ? ? 闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 很显然,几乎了解不了闭包的意思(这里对百度没有任何不好的言论导向),也不知道闭包的有关信息。所以我们从闭包的生成原因来探究 什么是闭包? 1.闭包的形成 首先我们来看其他互联网平台对闭包的解释 闭包:指有权访问另一个函数作用域中变量的函数。 什么是作用域? 当我们声明一个函数的时候,会自动生成一个它的作用域。
例如声明了一个函数fun1() 。我们之前讲过一个概念叫做对象,那么这个fun1()它就是个对象,既然是对象那就有他的属性,在JavaScript引擎中会自动生成一个属性[[scope]],这个玩意叫做作用域,是个隐式属性我们无法去直接调用它,是JavaScript引擎去存取的。
function fun1(){
var a = 10;
console.log(a);
}
在作用域里面有一个作用域链 scope chain,它是所有执行期上下文对象的集合,呈链式链接; 例如该函数就会生成一个我们看不见的作用域,里面就存取了一个作用域链(scope chain),它的第0位指向Global Object,是全局的一个执行上下文,它存储着一些基本信息,其中就有一个fun1,值为funuction; 然后我们执行这个函数
fun1();
这个时候系统就会去找fun1的作用域,然后再去找它的作用域链,首先是第0位,是GO(Global Object),在这里之前有个预编译环节,我们先不讲,实际这个时候不是GO。然后我们声明了一个变量a,它也有一个执行期上下文,这里它叫做AO;然后这个AO它就到了第零位(是被该位置的指针指向AO的),而GO在第一位;很显然 这是个 栈 结构,那我们就明白了这个函数的背后逻辑。( 这里补充一下AO里面存的是a,值为10) 我们再看这个函数
function fun1(){
var a = 10;
function fun2(){
console.log(a);
}
return fun2();
}
fun1();
按照刚才的逻辑再来一遍,当我们声明fun1的时候会生成它的GO在作用域链的第0位;执行fun1的时候会生成自己的一个AO在第0位,它的GO就到了第二位;这时候fun1的A0里面存着a和fun2 以及它们的值10和function;然后预编译到fun2的时候(注意这里没有执行fun2),fun2是在fun1的AO里面,就相当于fun1的GO;fun2也要生成一个自己的AO,我们叫做AO2; 这时候 fun1的作用域链指向了两个执行上下文分别是第0位的AO和第1位的GO,fun2的作用域链指向了两个执行上下文分别是第0位的AO2和第1位的AO。如下:
函数 | 执行上下文第0位 | 执行上下文第1位 |
---|
fun1 | AO | GO | fun2 | AO2 | AO |
这个时候在执行fun1,按理来说是不会输出a的值的,因为我们没有执行fun2,但事实是 输出了10。为什么呢? 我们在fun1中定义的局部变量a为什么会被fun2中的语句执行,并且未执行fun2; 这就是闭包产生的效果,当执行完fun1时,它会立即销毁它的执行上下文AO,这时候找不到a的值了;但是fun2的第1位我们可以找到AO;那有疑问了 fun2为什么还有啊?我们说一个函数它的执行上下文是函数执行一次生成一个,执行完立马被销毁,但是,我们压根没执行fun2啊,所以当fun1执行完的时候a已经随着执行上下文AO被销毁了,但是在fun2中的作用域链里的第1位仍指向AO,延长了AO的存在时间。我们再来看这句话 闭包: 指有权访问另一个函数作用域中变量的函数。这里的fun2可以访问fun1里的作用域里的变量a,其实这句话里面省略了 作用域链及指向的执行上下文AO 这就产生了闭包 ; 我们再看几个例子
function click_times() {
var i=1;
return function(){
alert(i++)
}
}
这个就是利用闭包制作的一个累加器使内部函数的AO一直访问,AO里面有外部函数的变量,也就是说闭包 当内部函数访问外部函数的变量的时候就会产生闭包。 那么如此来看闭包可以做很多事情,但是我们在写JavaScript的代码的时候避免不了产生闭包,那么闭包有什么不好的地方呢? 我们从它的产生原因来看,它的外部函数AO虽然会在该函数执行结束后销毁,它被销毁了,但并没有完全销毁,因为内部函数还是会指向AO,但我们已经用不到它了呀,那它所占的内存没有及时得到释放,就会发生内存泄漏,那当我们不需要闭包的时候,但又不得不产生闭包的时候,该怎么办呢? ?? ? ? ? ? ? ? ? ? ? ? ? 立即执行函数! ? ? ? 如何解决闭包问题 ? ? 详看下期讲解
|