我从来不理解JavaScript闭包,直到有人这样向我解释它

正如标题所述,JAVAScript闭包对我来说一直有点神秘,看过很多闭包的文章,在工作使用过闭包,有时甚至在项目中使用闭包,但我确实是这是在使用闭包的知识 。
最近看到的一些文章,终于,有人用于一种让我明白方式对闭包进行了解释,我将在本文中尝试使用这种方法来解释闭包 。
准备【我从来不理解JavaScript闭包,直到有人这样向我解释它】在理解闭包之前,有个重要的概念需要先了解一下,就是 js 执行上下文 。
这篇文章是执行上下文 很不错的入门教程,文章中提到:

当代码在JavaScript中运行时,执行代码的环境非常重要,并将概括为以下几点:
全局作用域——第一次执行代码的默认环境 。
函数作用域——当执行流进入函数体时 。
(…) —— 我们当作 执行上下文 是当前代码执行的一个环境与作用域 。
换句话说,当我们启动程序时,我们从全局执行上下文中开始 。一些变量是在全局执行上下文中声明的 。我们称之为全局变量 。当程序调用一个函数时,会发生什么?
以下几个步骤:
  1. JavaScript创建一个新的执行上下文,我们叫作本地执行上下文 。
  2. 这个本地执行上下文将有它自己的一组变量,这些变量将是这个执行上下文的本地变量 。
  3. 新的执行上下文被推到到执行堆栈中 。可以将执行堆栈看作是一种保存程序在其执行中的位置的容器 。
函数什么时候结束?当它遇到一个return语句或一个结束括号} 。
当一个函数结束时,会发生以下情况:
  1. 这个本地执行上下文从执行堆栈中弹出 。
  2. 函数将返回值返回调用上下文 。调用上下文是调用这个本地的执行上下文,它可以是全局执行上下文,也可以是另外一个本地的执行上下文 。这取决于调用执行上下文来处理此时的返回值,返回的值可以是一个对象、一个数组、一个函数、一个布尔值等等,如果函数没有return语句,则返回undefined 。
  3. 这个本地执行上下文被销毁,销毁是很重要,这个本地执行上下文中声明的所有变量都将被删除,不在有变量,这个就是为什么 称为本地执行上下文中自有的变量 。
基础的例子在讨论闭包之前,让我们看一下下面的代码:
我从来不理解JavaScript闭包,直到有人这样向我解释它

文章插图
 
为了理解JavaScript引擎是如何工作的,让我们详细分析一下:
  1. 在第1行,我们在全局执行上下文中声明了一个新变量a,并将赋值为3 。
  2. 接下来就变得棘手了,第2行到第5行实际上是在一起的 。这里发生了什么? 我们在全局执行上下文中声明了一个名为addTwo的新变量,我们给它分配了什么?一个函数定义 。两个括号{}之间的任何内容都被分配给addTwo,函数内部的代码没有被求值,没有被执行,只是存储在一个变量中以备将来使用 。
  3. 现在我们在第6行 。它看起来很简单,但是这里有很多东西需要拆开分析 。首先,我们在全局执行上下文中声明一个新变量,并将其标记为b,变量一经声明,其值即为undefined 。
  4. 接下来,仍然在第6行,我们看到一个赋值操作符 。我们准备给变量b赋一个新值,接下来我们看到一个函数被调用 。当看到一个变量后面跟着一个圆括号(…)时,这就是调用函数的信号,接着,每个函数都返回一些东西(值、对象或 undefined),无论从函数返回什么,都将赋值给变量b 。
  5. 但是首先我们需要调用addTwo的函数 。JavaScript将在其全局执行上下文内存中查找名为addTwo的变量 。噢,它找到了一个,它是在步骤2(或第2 - 5行)中定义的 。变量add2包含一个函数定义 。注意,变量a作为参数传递给函数 。JavaScript在全局执行上下文内存中搜索变量a,找到它,发现它的值是3,并将数字3作为参数传递给函数,准备好执行函数 。
  6. 现在执行上下文将切换,创建了一个新的本地执行上下文,我们将其命名为“addTwo执行上下文”,执行上下文被推送到调用堆栈上 。在addTwo执行上下文中,我们要做的第一件事是什么?
  7. 你可能会说,“在addTwo执行上下文中声明了一个新的变量ret”,这是不对的 。正确的答案是,我们需要先看函数的参数 。在addTwo执行上下文中声明一个新的变量``x```,因为值3是作为参数传递的,所以变量x被赋值为3 。
  8. 下一步是:在addTwo执行上下文中声明一个新的变量ret 。它的值被设置为 undefined(第三行) 。


    推荐阅读