前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【译】JavaScript全局变量的运行机制

【译】JavaScript全局变量的运行机制

作者头像
腾讯IVWEB团队
发布2020-06-27 21:59:10
7960
发布2020-06-27 21:59:10
举报

原文地址:How do JavaScript’s global variables really work? 作者:Dr. Axel Rauschmayer

在这篇博客中,我们会探究JavaScript全局变量的运行机制。其中,有些有趣的现象将会起到关键作用,如作用域范围、全局对象等等。

1 作用域

一个变量能被程序所访问到的范围就是其词法作用域,简称作用域。Javascript的作用域是静态的,即不会在运行时改变,而且允许嵌套。例如:

代码语言:javascript
复制
function func() { // (A)
  const foo = 1;
  if (true) { // (B)
    const bar = 2;
  }
}

if 语句(B行)引入的作用域嵌套在函数func(A行)的作用域中。

某个作用域 S 的最近包含范围称为 S 的外部作用域。在上述示例中,if 的外部作用域就是函数 func。

2 词法环境

在JavaScript语言规范中,作用域是通过词法环境实现的。其由两个部分组成:

  • Environment Record,环境记录标记了变量名所对应的变量值,例如字典Map,这是Javascript存储变量的地方。在Environment Record中,一个键值对就被称为一个绑定。
  • Outer Environment,对外部环境的引用就代表当前环境作用域的外部作用域。

因此,嵌套的上下文环境就是嵌套的作用域,并由外部引用相互链接。

3 全局对象

属性为全局变量的对象称为全局对象,其有几个不同的名字:

  • 通用名称(推荐使用):globalThis
  • 其它名称取决于平台和语言构造
  • window:是引用全局对象的经典方式,但是它只能运行在浏览器环境中,并不适用于Nodejs和Web Workers(可与普通浏览器脚本同时运行的进程)。
  • self:在浏览器环境中(包括Web Workers)随处可见,但是Nodejs不支持。
  • global:仅在Nodejs中可用。

全局对象包含所有内置的全局变量。

4 全局环境

全局作用域就是最外层的作用域,即不在有外部作用域,其对应的环境就是全局环境。每个环境通过一系列的外部引用链最终和全局环境相关联,而全局环境的外部引用就是null。

全局环境结合了两个环境记录(可参考下图):

  • 普通(声明性)环境记录
  • 对象环境记录,其使用起来和普通环境记录一样,区别在于对象环境记录会绑定一个对象并与其保持数据同步。在全局环境的情况下,这个对象就是全局对象

数据结构

接下来将说明如何将对象记录和声明记录组合在一起。

4.1 创建变量

为了创建一个真正的全局变量,该变量必须在全局作用域范围内,即处于脚本执行环境的顶层。例如:

  • 在全局环境的声明记录中创建顶层的 const、let 以及 class 绑定
  • 在全局环境的对象记录中创建顶层的 var 和函数声明绑定
代码语言:javascript
复制
<script>
  const one = 1;
  var two = 2;
</script>
<script>
  // All scripts share the same top-level scope:
  console.log(one); // 1
  console.log(two); // 2

  // Not all declarations create properties of the global object:
  console.log(window.one); // undefined
  console.log(window.two); // 2
</script>

此外,全局对象包含所有内置的全局变量,并通过对象记录将它们提供给全局环境。

4.2 获取/设置变量

若一个变量在两个环境记录中都存在绑定关系,当需要获取/设置该变量时,将会优先取声明性记录中的该变量。例如:

代码语言:javascript
复制
<script>
  let foo = 1; // declarative environment record
  globalThis.foo = 2; // object environment record

  console.log(foo); // 1 (declarative record wins)
  console.log(globalThis.foo); // 2
</script>

5 模块环境

每个模块都有自己的环境,它存储所有顶层声明——包括导入的。模块环境的外部环境就是全局环境。

6 结论:为什么JavaScript同时具有普通的全局变量和全局对象?

全局对象的存在通常被认为是一个错误,因此,新的语法规范中(如const、let和class)可以创建普通的全局变量(在脚本作用域中)。

幸运的是,现在通过JavaScript编写的代码大多数都位于ECMAScript模块和CommonJS模块中,而每个模块都有自己的作用域范围。这就是为什么全局变量的相关规范对于基于模块编写的代码没太大意义。

7 延伸阅读

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 作用域
  • 2 词法环境
  • 3 全局对象
  • 4 全局环境
    • 4.1 创建变量
      • 4.2 获取/设置变量
      • 5 模块环境
      • 6 结论:为什么JavaScript同时具有普通的全局变量和全局对象?
      • 7 延伸阅读
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档