JavaScript 作用域与闭包

发布于 2023-04-12 20:18:19 字数 2480 浏览 80 评论 0

作用域和闭包一直是 JS 中比较高级的内容,这篇文章打算以图的形式,让大家真正理解作用域和闭包的内容。

作用域

作用域(即 scope,其实更确切地说是 lexical scope)就是一套变量访问规则,这些规则包括变量如何存储和访问,也就是规定了哪些变量可以被访问,哪些变量不可以被访问。

假设有如下代码:

function foo(a) {
  if (typeof a === "number" || a instanceof Number) {
    const b = a + 1;
    console.log(b);
  }
}
foo();

我们来看下这段代码。 这段代码在 JS 引擎执行的时候究竟发生了什么? 这里我画了个图:

如上图,左边部分是编译器。 右半部分是作用域链。上述代码执行的具体过程大概是:

  • JS 源代码经过语法分析,转化成 tokens
  • tokens 经过语义分析,转化为 AST(抽象语法树)
  • 抽象语法树会被转化为字节码
  • JS 运行时开始运行这段上面生成代码
  • 当代码执行到函数声明的时候,引擎会向 scope chain 询问(一个 RHS)foo 是否已经声明 在这里是没有声明,会在当前 scope(也就是 global scope)创建一个 foo

    console 是 内置对象, 虽然不是我们声明的,但是它已经在全局作用域了。

  • 执行 foo。 引擎同样会询问 scope chain(一个 RHS),foo 是否已经声明。 在这里是声明了,如果没声明会报 Reference Error
  • 代码进到了 foo, 我们创建一个新的作用域,这个作用域指向全局作用域,从而形成作用域链。
  • 下次引擎发送 RHS,如果当前作用域找到就返回,找不到就沿着链找,最终都找不到就报 Reference Error, 过程类似原型链。
  • 剩下的我就不解释了,应该能看懂

注意图中块级作用域的位置,这也就解释了,为什么块级作用域声明的变量在块外面是无法访问的。上述过程忽略了一些细节,比如生成 optimized AST 和 optimized byte code 的过程

事实上,作用域背后地原理是 词法环境, 词法环境由两部分组成:

  1. 环境记录, 这其实就是JavaScript用来存变量地地方,一个 key-value 对在这里被成为一个 binding。
  2. 外部环境的引用

其实它就是一个递归的数据结构,是不是有像刚才我们画地作用域?

我们需要特殊注意的是全局作用域,这是一个特殊的作用域,总是出现在作用域的最外层。全局作用域 对应的环境就是全局环境,全局作用域的外部环境引用是null。是不是感觉和原型链什么的都很像?

闭包

闭包就是当一个函数即使是在它的词法作用域之外被调用时,也可以记住并访问它的词法作用域。

从理论上来说JS 中一切函数都有闭包,其原因就是 JS 和大多数编程语言一样采用的是静态作用域.

但是我们通常谈论的是可观察的闭包,什么是可观察? 我们来举个例子,这是一个可观察的闭包例子:

function foo(a) {
  const c = "closures";
  if (typeof a === "number" || a instanceof Number) {
    const b = a + 1;
    console.log(b);
  }
  return () => c;
}
const func = foo();
func(); // 'closures'

上面的代码 foo 作用域的 c 在 foo 的外侧被访问到了,这就是一个 可观察 的闭包.

为什么呢? 这和上面的说的好像不太一样? 不,是一样的。我同样画了一个图:

说的直白一点就是 foo 返回的函数 记住了 ta 被定义的时候的作用域,因此你可以访问到 foo 里面定义的变量。 看起来好像是 突破了作用域的限制,我们称之为 可观察 的闭包。

当然没有被这个返回的函数引用的变量还是会被 GC 销毁

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

魔法少女

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文