什么是闭包?
MDN 是这样说的:
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
说人话就是:
如果一个内层函数访问到其外层函数的作用域,那么这个函数加这个变量就叫做闭包。
可以简单将闭包理解为“定义在一个函数内部的函数,可以读取其外部函数内部的变量”。
闭包最大的特点就是能保存它出生的环境。
for(var i = 0; i < 5; i++) {
!function(i) {
setTimeout(function () {
console.log(i);
});
}(i)
}
// 0
// 1
// 2
// 3
// 4
上例通过闭包使函数继续访问它定义时的作用域。而这个新生成的作用域将每一次循环的当前 i 值单独保存了下来。
闭包的用途是什么?
-
读取外层函数内部的变量
function f1() { var n = 999; function f2() { console.log(n); } return f2; } var result = f1(); result(); // 999
由于 f2 在 f1 内部,因此可以读取 f1 内部的变量。
此时我们把 f2 作为返回值,就可以在 f1 外部读取它的内部变量了。
-
让变量始终保持在内存中,每次调用都是继承上一次
function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); inc() // 5 inc() // 6 inc() // 7
通过闭包,把createIncrementor
函数内部的star
变量保留下来,每次调用函数都是在上一次调用的基础上进行计算。
-
模拟对象的私有属性和私有方法
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = Person('张三'); p1.setAge(25); p1.getAge() // 25
函数Person
的内部变量_age
,通过闭包getAge
和setAge
,变成了返回对象p1
的私有变量。
闭包的缺点是什么?
闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
因为外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。使用不当容易造成内存泄露。