查看原文
其他

【英】JavaScript的全局变量是如何工作的?

Rauschmayer 前端早读课 2019-12-16


前言

看来对纯英文蛮多人是不抗拒的。本期由@Dr. Axel Rauschmayer分享。

英文从这开始~~

In this blog post, we examine how JavaScript’s global variables work. Several interesting phenomena play a role: the scope of scripts, the so-called global object, and more.

Scopes

The lexical scope (short: scope) of a variable is the region of a program where it can be accessed. JavaScript’s scopes are static (they don’t change at runtime) and they can be nested – for example:

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

The scope introduced by the if statement (line B) is nested inside the scope of function func() (line A).

The innermost surrounding scope of a scope S is called the outer scope of S. In the example, func is the outer scope of if.

Lexical environments

In the JavaScript language specification, scopes are “implemented” via lexical environments. They consist of two components:

  • An environment record (think dictionary) that maps variable names to variable values. This is where JavaScript stores variables. One key-value entry in the environment record is called a binding.

  • A reference to the outer environment – the environment representing the outer scope of the scope represented by the current environment.


The tree of nested scopes is therefore represented by a tree of nested environments, linked by outer references.

The global object

The global object is an object whose properties are global variables. (We’ll examine soon how exactly it fits into the tree of environments.) It has several different names:

  • Everywhere (proposed feature): globalThis

  • Other names for the global object depend on platform and language construct:

    • window: is the classic way of referring to the global object. But it only works in normal browser code; not in Node.js and not in Web Workers (processes running concurrently to normal browser code).

    • self: is available everywhere in browsers, including in Web Workers. But it isn’t supported by Node.js.

    • global: is only available in Node.js.


    The global object contains all built-in global variables.

The global environment

The global scope is the “outermost” scope – it has no outer scope. Its environment is the global environment. Every environment is connected with the global environment via a chain of environments that are linked by outer references. The outer reference of the global environment is null.

The global environment combines two environment records:

  • An object environment record that works like a normal environment record, but keeps its bindings in sync with an object. In this case, the object is the global object.

  • A normal (declarative) environment record.


The following diagram shows these data structures. Script scope and module environments are explained soon.



The next two subsections explain how the object record and the declarative record are combined.

Creating variables

In order to create a variable that is truly global, you must be in global scope – which is only the case at the top level of scripts:

  • Top-level const, let, and class create bindings in the declarative record.

  • Top-level var and function declarations create bindings in the object record.

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

Additionally, the global object contains all built-in global variables and contributes them to the global environment via the object record.

Getting or setting variables

When we get or set a variable and both environment records have a binding for that variable, then the declarative record wins:

<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

Each module has its own environment. It stores all top-level declarations – including imports. The outer environment of a module environment is the global environment.

Conclusion: Why does JavaScript have both normal global variables and the global object?

The global object is generally considered to be a mistake. For that reason, newer constructs such as const, let, and classes create normal global variables (when in script scope).

Thankfully, most of the code written in modern JavaScript, lives in ECMAScript modules and CommonJS modules. Each module has its own scope, which is why the rules governing global variables rarely matter for module-based code.

Further reading

  • Sect. “Lexical Environments” in the ECMAScript specification provides a general overview over environments.

  • Sect. “Global Environment Records” covers the global environment.


关于本文

作者:@Dr. Axel Rauschmayer
原文:https://2ality.com/2019/07/global-scope.html

为你推荐


【第1255期】超大型 JavaScript 应用的设计哲学


【第1351期】JavaScript 中的私有变量

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存