【译】JavaScript的全局变量到底是怎么工作的

简介: 【译】JavaScript的全局变量到底是怎么工作的

原文标题:How do JavaScript’s global variables really work

地址:https://2ality.com/2019/07/global-scope.html


作用域


一个变量的词法作用域(简称作用域)是指:在程序的这个区域内可以访问到该变量。JavaScript的作用域是静态的(运行时不会改变),并且是可以嵌套的。例如:

function func() { // (A)
 const foo = 1;
 if (true) { // (B)
   const bar = 2;
}
}

由 If语句(B行) 创造的作用域是嵌套在函数func(A行)内的。

包含作用域S的外围作用域中最内部的作用域被称为S的外部作用域。在上面的例子中,func的作用域就是if的外部作用域。


Lexical environments(词法环境)


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

  • 一个environment record(环境记录,考虑成一个字典),变量名到变量值的映射。这是JavaScript保存变量的地方。一个在环境记录中的key-value入口被称作一次binding(绑定).
  • 一个对outer environment(外部环境)的引用 —— 表示当前环境所处的作用域的外部作用域的环境


因此,一个嵌套的作用域树可以由一个嵌套的、由外部引用连接的environment树(环境树)表示。


全局对象


全局对象的属性都是全局变量。(我们一会儿将研究它到底是如何与环境树相适应的)。全局对象有不同的名字:


  • 在所有环境中(提议中的future):globalThis
  • 根据平台和语言接口的不同,全局对象有其他不同的名字:
  • window:表示全局对象的最典型的方式。但是window仅在浏览器中生效。Node.js和Web Workers中都无法使用window。
  • self:浏览器中都可以使用self表示全局对象,包括Web Workers。但是,Node.js不支持self。
  • global:仅在Node.js中可用。

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


The global environment(全局环境)


全局作用域是"最外部"的作用域 —— 它没有外部作用域。它的环境是全局环境。所有的环境都通过一系列由外部引用连接的环境与全局环境相连。全局环境的外部引用为null。

全局环境结合了两个环境记录:

  • object environment record (对象环境记录):像normal environment record(普通环境记录)一样工作,但是会保持它的bindings(绑定)和一个对象同步。这个对象就是全局对象。
  • normal(declarative) environment record (普通声明环境记录)

下面的图表示了上述的数据结构。Script scope(脚本作用域)和 module environments (模块环境)将会在后面解释.

640.jpg

下面两个小结将会解释object record(对象记录)和declarative record (声明记录)是如何结合的。


创建变量


为了创建一个真正的全局变量,你必须处于全局作用域中 —— 这只是顶层脚本的情况:

  • 顶层的const 、let 和 class 会在 声明记录中创建绑定.
  • 顶层的 var 和 function 声明 会在对象记录中创建绑定.


<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>


另外,全局对象包含了所有的内置全局变量,并且通过对象记录将全部变量提供给全局环境。


获取、设置变量


当我们想要获取或设置一个在声明环境记录和对象环境记录都存在绑定的变量时,会优先操作声明环境记录。

<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>


Module environments(模块环境)


所有的模块都有自己的环境。它保存了所有顶级的声明 —— 包括imports。一个模块环境的外部环境就是全局的环境。


结论:为什么JavaScript即有正常的全局变量也有全局对象?


全局对象一般被认为是一个错误。因此,最新的const, let, 和 class 会创建正常的全局变量 (在script scope中时) 。


值得庆幸的是,大多数用现代JavaScript编写的代码都存在于ECMAScript模块和CommonJS模块中。每个模块都有自己的作用域,这就是为什么控制全局变量的规则对于基于模块的代码很少重要的原因。


相关文章
|
3月前
|
JavaScript 前端开发 安全
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(三)
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量
|
3月前
|
存储 JavaScript 前端开发
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(一)
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量
|
3月前
|
JavaScript 前端开发
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(二)
闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量
|
4月前
|
JavaScript 前端开发
js中this是指向的哪个全局变量,改变this指向的方法有什么
js中this是指向的哪个全局变量,改变this指向的方法有什么
19 0
|
10月前
|
JavaScript 前端开发
【JS 经典面试题】全局变量和局部变量
【JS 经典面试题】全局变量和局部变量
77 1
|
存储 自然语言处理 JavaScript
JS全局变量
1. Scope(作用域) 2. Lexical Environments (词法环境) 3. 全局对象(global object) 4. 浏览器环境下的globalThis 5. 全局环境(global envrionment) • Script 作用域 和Module 作用域 • 生成变量: 声明环境记录 vs 对象环境记录 • 访问变量 • 全局ECMAScript变量和全局宿主变量 6. 一图胜前言
|
JavaScript 前端开发
JavaScript 全局变量
JavaScript 全局变量
54 0
|
JavaScript 前端开发 Java
JavaScript相关面试题:1.js数据类型;2.JavaScript 语句的基本规范;3.事件代理;4.全局变量;5.哪些操作会造成内存泄漏;6.bind, call,apply
★三者都可以改变函数的this对象指向 ★三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window ★三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入 ★bind 是返回绑定this之后的函数,apply 、call 则是立即执行
148 0
|
JavaScript 开发者
node.js 全局变量说明
node.js 全局变量说明
140 0
node.js 全局变量说明
|
存储 JavaScript 前端开发
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置