闭包
闭包
定义
闭包是指有权访问另外一个函数作用域中的变量的函数。——《JavaScript高级程序设计》
函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。——MDN
例子
举个栗子:
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
上述代码是MDN中的样例代码,在makeFunc函数内部定义了一个displayName的函数,并将其作为返回值。在displayName中,其执行的功能是弹窗显示makeFunc中的定义的变量name。抛开代码细节,从上述代码实现的功能也就是将name输出。
你可能觉得上述写法过于冗长,多此一举,你可能会写出如下更加精简的代码。
function makeFunc() {
var name = "Mozilla";
alert(name);
}
makeFunc();
但是,现在增加了一个需求,在显示完name
之后,在name
名称后面添加一个!
号。
如果沿用刚才改写过的代码的话,你需要改写成如下代码:
var name = "Mozilla";
function makeFunc() {
alert(name);
name += '!';
}
makeFunc();
makeFunc();
因为如果不将var name移到makeFunc外部的话,当你调用makeFunc结束后,函数内部变量将被垃圾回收机制回收,无法实现添加!的功能。但是这样带来的坏处是污染全局的名称空间且全局中的任意函数都能调用到name,而且如果我想对于另外一个name做同样的操作,则需要创建新的变量名加以区分。
如果我们使用最开始的代码的话,我们只需要改写成如下形式:
function makeFunc() {
var name = "Mozilla";
function displayName() {
console.log(name);
name += '!';
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
myFunc();
可以理解为我们将name作为了makeFunc()的私有变量,var myFunc = makeFunc();
创建了一个词法环境,这个词法环境不会在第一次调用后销毁。displayName
和displayName所处的词法环境
就构成了一个闭包.
闭包产生的条件
从上面的例子中我们大致能了解到闭包产生的条件:
- 存在函数嵌套;
- 嵌套的内部函数必须引用在外部函数中定义的变量;
- 嵌套的内部函数必须被执行。
闭包的作用
同时我们也能了解到闭包的作用:
-
变量常驻内存,对于实现某些业务很有帮助,比如计数器之类的。
-
架起了一座桥梁,让函数外部访问函数内部变量成为可能。
-
私有化,一定程序上解决命名冲突问题,可以实现私有变量
但是缺点是变量一直存在于内存中,无法被释放,可能随着这些碎片的累计会造成内存溢出。
释放内存
那么如何释放内存呢?
以上述例子为例,令myFunc=null
即可。