1 闭包的概念
下面我们看看MDN中是怎么定义的:
函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。
这段话的重点在:从内部函数访问外部函数作用和创建函数会在内部生成闭包。但还是很抽象,具体的应该怎么理解,还是要看代码
function a() {
var id = '13234';
function b() {
console.log(id);
}
b();
}
a(); // '13234'
看这段代码, id是一个局部变量,b也是a内部的一个函数,对于b这个函数来说, a属于他的外部, b可以访问到它外部的一个变量id,说明b就是一个闭包。
2 产生闭包的原因-JavaScript特殊的变量作用域
一方面,在JS中 函数可以直接读取全局变量
var a = 'zhangan'
function b() {
console.log(a) //'zhangan'
}
另一方面,函数外部无法读取函数内部的变量
function c(){
var d = 'name'
}
c(d) // error: d is not defined
外部怎么获取内部局部变量
在有些情况下,我们需要在外部访问到内部的局部变量,这时候闭包就可以用上了。
function e() {
var f = '12345'
g() {
console.log(f)
}
return g()
}
e()()
在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
3 闭包的用处
- 1、在外部读取函数的内部变量,如上面的例子
- 2、将这些变量的值始终缓存在内存中。
function h() {
var n = 1;
add = function() {
n += 1
}
function i() {
console.log(n);
}
return i
}
var res1 = h()
res1() // 1
add()
res1() // 2
上面这个例子,h是i的父函数,i被赋予了一个全局函数,导致i函数一直在内存中,i函数依赖h函数,所以h函数也始终在内存中,add是一个全局函数,且的值是一个匿名函数,而这个匿名函数本身也是一个闭包,所以add相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
4 使用闭包的一些注意事项
内存占用问题
通常函数的作用域和变量会在调用函数后立即销毁,但是闭包的特殊机制造成闭包对内存的占用会直到闭包不存在为止。 解决的办法就是在使用完之后,将所有的闭包主动销毁。
对变量的占用
有时候闭包造成的变量占用,也需要将此变量重新销毁。 比如
(function () {
var a = 0;
setInterval(function() {
console.log(a++);
},1000);
})();