我们可能没有发现自己正在使用闭包
一、为什么写这篇文章
之前也写过关于闭包的文章。使用了上下文,使用了[[立即执行函数]],使用了AO、GO,甚至还使用到了[[堆内存]]来进行解释。
自己看都愣半天。啥是堆内存了?AO和GO又是什么玩意儿?
我用了一些更高深莫测的词汇来解释一个概念,而这些词汇的知识点甚至比当前要解释的概念更多。莫说当时,即便是现在,我也难以解释清楚。
如此显然很蠢!
都说要学习技术类文章的话,相比中文,更应该看英文的。中文博大精深,模凌两可的着实多。通俗易懂才是王道,这也应该是我们写文章的目标。
所以就又有了解析闭包的文章。
二、闭包是什么
闭包由closure翻译而来。

它的含义更多的是闭,而不是包.
前端是一个重视实践的技术活,所以我们来看下面这是闭包的例子,并从中找规律。
1. 第一段代码,常见的闭包,直接返回一个函数:
function foo() {
let local = 1
return function() {
local++
console.log(local)
}
}
const fn = foo()
fn() // 2
fn() // 3
2. 第二段代码,循环赋值 + IIFE:
for(var i = 0; i < 10; i++) {
(function() {
setTimout(function() {
console.log(i) // 0, 1, 2, 3, 4,5。。。
}, 1000)
})()
}
3. 第三段代码,全局应用函数:
function foo() {
let local = 1
window.addLocal = function() {
local++
console.log(local)
}
}
addLocal() // 2
addLocal() // 3
4. 第四段代码,函数返回对象函数:
function foo() {
let local = 1
function too() {
local++
console.log(local)
}
function eoo() {
local++
console.log(local)
}
return [too, eoo]
}
const a = foo()
a[0]() // 2
a[0]() // 3
a[1]() // 4
上面段代码都实现了局部变量没有销毁的作用,假设已知它们都是闭包,都有一些什么规律呢?
一定需要return么?
不需要。第三段代码中,就没有return
一个函数出去,但是它依旧实现了保存变量的功能。由此可知,return
并不是必须的。它的作用只是为了让闭包可以运行。
不管是return
出去,还是直接挂载到window
上面,都是为了在函数外面可以运行。
一定是函数嵌套函数么?
显然不是。正如第二段代码,既然都说第二段代码中的函数也是闭包的话。它是一个立即执行函数。所以说,函数嵌套函数的作用显然是为了达到隐藏变量的目的。
三、我们平时自然而然的就使用到的了闭包。
我们可能没有发现自己正在使用闭包。
根据上面的推论,四段代码都是根据变量是否正确的自增来作为是否是闭包的标准。而这也正式闭包的作用,它使得local
这变量没有暴露出来。
所以说,闭包的作用就是为了隐藏变量!
那么闭包的最小单位就是:
let local = 1
function foo() {
console.log(local)
}
而这一段代码片段为了不让变量变成全局变量。我们可以给它添加IIFE:
;(function(){
let local = 1
function foo() {
console.log(local)
}
})()
这就是为什么说我们平时一直都在使用闭包。
闭包是 JS 函数作用域的副产品,所以《高程》上面说了解闭包就要先理解什么是函数作用域。它是 由函数和这个函数可以访问到的变量这两者构成的。
四、为什么都说需要谨慎的使用闭包
百度一下,也不知道谁抄的谁,太多一模一样的文章。而我也是长期这么认为的。
根据我之前写的闭包的文章,闭包长期存在于GO当中,自然可能会占用内存,如果数量过多了,不就导致内存泄漏了么?
看起来挺有道理的,这是因为我不懂啥啥叫[[内存泄漏]],差产生的误解。所以我上网搜索到了如下的回答:


也就是说,对于闭包而言,造成内存泄漏的不是闭包本身,而是IE浏览器。
转载自:https://juejin.cn/post/7197053309105602616