javascript之闭包一(JavaScript 引擎的工作原理)

573 阅读6分钟

关于闭包的文章网上有很多,我们都知道闭包很重要但是很难理解。越看越迷糊,感觉看的似懂非懂,过不了多久就又忘了。为了理清楚闭包的来龙去脉,我整理了闭包的文章,由于我系统的整理了闭包,所写的内容有些多,故将本篇文章共分三部分进行讲解。期望对跟我有同样困惑的前端人有所帮助! 本文的目标:彻底理解闭包的由来,掌握闭包知识,能够熟练应用,揭开闭包的神秘面纱,深入理解闭包。我们将从4个方面逐步讲解。

内容介绍:

  1. 闭包的由来
  2. 闭包的知识点
  3. 闭包的示例应用
  4. 总结

一、闭包的由来

在理解闭包之前,需要先理解一些概念,执行上下文就是其中的一个。我会写一篇文章中对执行上下文进行讲解。现在先简单解释下,在运行 JavaScript 代码时,它的运行环境是非常重要的,运行环境可能是如下几种中的一种:如:全局代码——首次执行代码的默认环境。函数代码——每当执行流程进入函数体时……我们将执行上下文定义当前代码的执行环境或作用域。

换句话说,当我们启动程序时,我们从全局执行上下文开始。我们在全局执行上下文中声明一些变量,这些变量为全局变量。当程序调用函数时,会发生以下几个步骤:1、JavaScript 创建一个新的本地执行上下文。 2、本地执行上下文将拥有自己的变量集。

3、新的执行上下文被抛到执行栈上。我们可以将执行栈视为一种用于跟踪程序执行位置的机制。

函数会在遇到 return 语句或结束括号}时结束执行,并发生以下情况:

1、本地执行上下文从执行栈中跳出。

2、函数将返回值发送给调用上下文。调用上下文是调用此函数的执行上下文,它可以是全局执行上下文或另一个本地执行上下文。调用上下文将负责处理返回值,返回值可以是对象、数组、函数、布尔值或其他任何东西。如果函数没有 return 语句,则返回 undefined。

3、本地执行上下文被销毁,这个很重要。在本地执行上下文中声明的所有变量都将被删除,它们不再可用,这就是为什么它们被称为局部变量。

第一部分内容介绍:

  1. 理解js引擎的工作原理
  2. 了解词法作用域
  3. 理解返回函数的函数
  4. 闭包的出现

一、理解 JavaScript 引擎的工作原理

我们先看一段代码,是如何运行的呢?

 let a = 3
 function addTwo(x) {
   let ret = x + 2
   return ret
 }
 let b = addTwo(a)
 console.log(b)

为了理解 JavaScript 引擎的工作原理,我们进行详细分析下:

  1. 在第 1 行,我们在全局执行上下文中声明一个新变量 a,并将它的值赋为数字 3。

  2. 在第 2 行到第 5 行,我们在全局执行上下文中声明了一个名为 addTwo 的新变量,并为其分配了一个函数定义,{}之间的内容被分配给了 addTwo。函数内部的代码不会被执行,只是存储在变量中以备将来使用。

  3. 第 6 行,我们在全局执行上下文中声明了一个新变量,并将其标记为 b。声明变量后,它的值为 undefined。

  4. 接下来,仍然是第 6 行,我们看到了一个赋值运算符。我们准备为变量 b 分配一个新值。接下来,我们看到一个被调用的函数。当你看到一个变量后面跟着圆括号 (...) 时,就表示在调用一个函数。从函数返回的任何内容都将被分配给变量 b。

  5. 但首先我们需要调用被标记为 addTwo 的函数。JavaScript 将在其全局执行上下文内存中查找名为 addTwo 的变量。它找到了,也就是在步骤 2(或第 2-5 行)中定义的那个。变量 addTwo 包含了一个函数定义。请注意,变量 a 被作为参数传递给该函数。JavaScript 在其全局执行上下文内存中搜索变量 a,找到它,发现它的值为 3,然后将数值 3 作为参数传递给该函数。准备执行该函数。

  6. 现在切换执行上下文,创建了一个新的本地执行上下文,我们将其命名为“addTwo 执行上下文”。执行上下文被推送到调用栈。我们在本地执行上下文中做的第一件事是什么?

  7. 你可能会想说,“在本地执行上下文中声明了一个新的变量 ret”。但其实不是这样的,我们首先需要查看函数的参数。在本地执行上下文中声明了一个新变量 x,又因为 3 被作为参数传递进来,所以变量 x 被赋值为 3。

  8. 下一步:在本地执行上下文中声明新的变量 ret,其值设置为 undefined。(第 3 行)仍然是第 3 行,需要执行一个加法运算。首先,我们需要 x 的值,JavaScript 会尝试查找变量 x,它首先查看本地执行上下文。它找到了,值为 3。第二个操作数是数值 2,加法的结果(5)被赋给变量 ret。

  9. 第 4 行,我们返回变量 ret 的内容。在本地执行上下文中进行另一个查找。ret 包含值 5。函数返回数值 5,函数结束执行。

  10. 第 4-5 行,函数结束执行,本地执行上下文被销毁,变量 x 和 ret 被清除,它们不再存在。上下文弹出调用栈,返回值被返回到调用上下文。在这种情况下,调用上下文就是全局执行上下文,因为函数 addTwo 是从全局执行上下文中调用的。

  11. 现在我们从在步骤 4 中暂停的位置继续。返回值(数值 5)被分配给变量 b。

  12. 在第 7 行,变量 b 的内容会在控制台中打印出来。在这个例子中,数值为 5。

  13. 对于一个非常简单的程序来说,这样的解释显得太过冗长,但我们甚至都还没有提到闭包。我保证会说到那里,但首先我们需要说一些其他的。