闭包 -> 个人理解

287 阅读3分钟

说在前面

因为不是太会写这类的博文,我只能将我自己的理解简单的表述出来。文章所有的仅代表我个人的理解~欢迎互相讨论

这篇文章的由来,源于一次面试,面试官问我什么是闭包,当时我的回答是内部的函数可以访问外部的变量,并且举了一个小例子。现在回过头来,我感觉我说的并不对,有问题。

闭包的定义 -> 个人理解

闭包它是指javascript内部的函数总是可以访问其所在环境的外部函数中声明的变量和参数,即使外部函数被返回了之后。 这是我目前对于闭包的定义的一个理解

当然,接下来的内容之前,建议先去了解js的词法环境~

首先,我需要知道,js中所有的函数在 出生 时都会记住此时创建它们的 词法环境 ,所有的函数都会拥有一个名为**[[Environment]]** 的隐藏属性,这个属性会保存创建函数时的记法环境的引用。通过这个外部的记法环境可以进行函数外部变量的访问。

理论依据:

ECMA-262文件,第8.1.2.4的第12条

Set the outer lexical environment reference of env to the value of F’s [[Environment]] internal slot.

ECMA-262文件 在第9.2条 表格中

[[Environment]] :The Lexical Environment that the function was closed over. Used as the outer environment when evaluating the code of the function.

所以,我在此时的理解是为在js中所有的函数都会默认拥有一个**[[Environment]]** 隐藏属性,都可以访问外部的变量。从而,我认为,我们js中所有的函数都是个闭包了。

代码理解

function counter(){
    let count = 0;
  return function(){
    return count++
  }
}
let test = counter();
test()
  1. 首先,我们看第 7 行,counter()被调用,它创建一个新的词法环境,然而我们还有一个外部的词法环境,这两个词法环境互相嵌套 下面这张图: 第一张图 箭头处三种不同颜色分别代表了:当前词法作用域、外部记法作用域、参数
  2. 我们再看,在红色区域内,还创建了一个嵌套的函数 return count++ ,忽略第8行,我们此时还仅仅是创建了它,但是并没有运行它。 聪明的人想到了,这个函数的[[Environment]]所保存的词法环境的引用就是上图中 counter()的词法作用域。 同样,我们忽略第8行代码:
  3. 这时,我们就应该知道,看第7行,test=counter(),那么,是不是就代表,我们的test是有对{count:0}的词法环境的引用(此时的test应该就是return过来的那个函数,这里不清楚的话我也没办法了)
  4. 此时,我们在第8行调用了test(),此时,创建一个新的词法环境,我们首先会在这个词法环境内寻找我们要使用的count,然而我们并没有发现,于时我们向**[[Environment]]** 所引用的外部词法环境counter中去寻找。这里,我们找到了count~
  5. 接下来的事情就简单了,我们不停地调用test(),然后我们会的count会不断地增加~