我们可能没有发现自己正在使用闭包

2,259 阅读1分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

一、为什么写这篇文章

之前也写过关于闭包的文章。使用了上下文,使用了[[立即执行函数]],使用了AO、GO,甚至还使用到了[[堆内存]]来进行解释。

自己看都愣半天。啥是堆内存了?AO和GO又是什么玩意儿?

image.png

我用了一些更高深莫测的词汇来解释一个概念,而这些词汇的知识点甚至比当前要解释的概念更多。莫说当时,即便是现在,我也难以解释清楚。

如此显然很蠢!

都说要学习技术类文章的话,相比中文,更应该看英文的。中文博大精深,模凌两可的着实多。通俗易懂才是王道,这也应该是我们写文章的目标。

所以就又有了解析闭包的文章。

二、闭包是什么

闭包由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 foo(j) {
    setTimout(function() {
      console.log(j) // 0, 1, 2, 3, 4,5。。。
    }, 1000)
  })(i)
}

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 函数作用域的副产品,所以《高程》上面说了解闭包就要先理解什么是函数作用域。它是 由函数这个函数可以访问到的变量这两者构成的。

四、为什么都说需要谨慎的使用闭包

百度一下,也不知道谁抄的谁,太多一模一样的文章。而我也是长期这么认为的。

截屏2023-02-07 00.17.30.png

根据我之前写的闭包的文章,闭包长期存在于GO当中,自然可能会占用内存,如果数量过多了,不就导致内存泄漏了么?

看起来挺有道理的,这是因为我不懂啥啥叫[[内存泄漏]],差产生的误解。所以我上网搜索到了如下的回答:

也就是说,对于闭包而言,造成内存泄漏的不是闭包本身,而是IE浏览器。