什么是闭包?
闭包是JS的一种语法特性。
闭包 = 函数 + 自由变量
对于一个函数来说,变量分为 全局变量、本地变量和自由变量。
let count = 0
function add(){
count += 1
}
把上述代码放在一个 【非全局环境】 里面就是一个闭包。
闭包不是count,闭包也不是add,闭包是count + add组成的整体。
即 函数 和 函数内部能访问到的变量 的总和就是一个闭包。
那怎么制造一个非全局环境呢?答案是 立即执行函数:
const add2 = function() {
let count = 0
function add(){
count += 1
}
}()
但是这个代码什么用也没有,所以我们需要return add
const add2 = function() {
let count = 0
return function add(){
count += 1
}
}()
此时add2其实就是add,我们可以调用add2。
add2()
// 相当于
add()
// 相当于
count += 1
至此,我们就实现了一个完整的闭包的应用。
为什么需要函数套函数呢?
因为需要局部变量,所以才把count放在一个函数里,如果不把count放在一个函数里面,count就是一个全局变量,就达不到使用闭包的目的-隐藏变量 了。
即嵌套函数的目的是创造一个局部变量,和闭包无关。
为什么要return add呢?
因为如果不return,就无法使用这个闭包,把 return add 改成 window.add = add 也是一样的,只要让外面可以访问到这个 add 函数就行了。
所以 return add 只是为了add能被使用,也和闭包无关。
解决了什么问题
- 避免污染全局环境。
- 提供对局部变量的间接访问。
- 维持变量,使其不被垃圾回收。
优点
简单,好用
缺点
如果 使用不当 可能造成内存泄漏。
注意是使用不当, 不是闭包。
「闭包造成内存泄露」这句话以讹传讹很多年了,是曾经旧版本 IE 的 bug 导致的问题。
举例说明:
function test() {
var x = {name: 'x'};
var y = {name: 'y', content: "-----这里很长,有一万三千五百个字符那么长----" }
return function fn() {
return x;
};
}
const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 请问,y 会消失吗?
对于一个正常的浏览器来说,y 会在一段时间后自动消失(被垃圾回收器给回收掉)。
但旧版本的 IE 并不是正常的浏览器,所以是 IE 的问题。