闭包(Closure)是由函数和与其相关的引用环境组合而成的实体。例如在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。也就是 「函数」和「函数内部能访问到的变量」(也叫环境)的总和
闭包只是形式和表现上像函数,但是并不是函数。函数在被定义之后就确定了,不会在执行时发生变化,所以函数只有一个实例。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。
创建闭包
只要在一个函数中再定义一个函数,这个内部函数就是一个闭包。
function add(y){
return function(x){
return x+y
}
}
function(x)的返回值,依赖于外部的自由变量y,add(y)就是包含自由变量y的环境,且js允许内部函数访问外部函数的的局部变量。此时add(y)就对function(x)构成了闭包。
看下一个例子:
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
和之前不同的是,内部函数displayName() 在执行前,就从外部函数返回。而代码可以正常运行。因为myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用。displayName 的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用。因此,当 myFunc 被调用时,变量 name 仍然可用,其值 Mozilla 就被传递到alert中。
加速:
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
makeAdder(x) 函数接受一个参数 x ,并返回一个新的函数。返回的函数接受一个参数 y,并返回x+y的值
闭包的作用
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
在 Web 中,这种情况特别常见。大部分我们所写的 JavaScript 代码都是基于事件的 — 定义某种行为,然后将其添加到用户触发的事件之上(比如点击或者按键)。我们的代码通常作为回调:为响应事件而执行的函数。
闭包的缺点
如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用时,方法都会被重新赋值一次(也就是,每个对象的创建)。