文章目录
闭包怎么延长了变量的生命周期呢?
- 我们知道,变量都是有作用域的:在JS中,如果在一个函数里边定义了一个变量(即局部变量),那么这个变量的作用域就是这个函数内部,也就是说只有在这个函数内部才可以访问该变量。
- 那么如果我们想要在函数外部访问这个变量呢?这个时候就可以用闭包,闭包的作用就是延长了局部变量的作用域。
那么闭包是什么呢?
在JavaScript权威指南中,是这样描述闭包的:函数对象可以和作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。
在JavaScript高级程序设计中,是这样描述闭包的:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
其实有点绕,但我们回到闭包的作用上去,为什么会有闭包呢?因为要延长变量的作用域,变量作用域被延长后我们就可以从一个函数外部去访问它内部的局部变量。问题又来了,怎么才可以延长变量作用域?一般是用嵌套函数,举个栗子:
/*定义一个函数Fn(),该函数内部有一个局部变量num = 1;
然后它返回值是一个函数fn()(即嵌套函数),这个嵌套函数内打印了num变量
num变量作用域是Fn函数内部,而fn是Fn的嵌套函数,所以fn可以访问到num;*/
function Fn() {
var num = 1;
return function fn() {
console.log(num);
}
}
// 调用Fn,并用fun接收其返回值,那么下列代码相当于:fun = fn
var fun = Fn();
// 调用fun,其实就是调用fn,因为上边让fun = fn了
fun() // 最后控制台打印的结果就是:1
/* 上述例子中,fun是在Fn函数外部的,但是调用fun却能打印出来
Fn中的局部变量num;也就是说从Fn函数外部访问到了其内部的变量num,
还可以说是局部变量num的作用域被延长了。
而我们是通过Fn函数内的嵌套函数fn才访问到num局部变量的,
也就可以看做是用fn将局部变量nun包裹了起来。
*/
在JavaScript权威指南中,有一个关于闭包和垃圾回收之间的关系的详细描述:我们将作用域链描述为一个对象列表,不是绑定的栈。每次调用JavaScript函数的时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。如果不存在嵌套函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。如果定义了嵌套函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么它们也会和所指向的变量绑定对象一样当做垃圾回收,但是如果这个函数定义了嵌套函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收,并且它所指向的变量绑定对象也不会被当做垃圾回收。
我觉得这段话从更底层去解释了闭包的实现原理。
参考链接:
原文 传送门