MeloGuo, translation
Back

由 Jordan Harband 提出的 ECMAScript 的新特性 globalThis 提供了一种获取全局对象的标准方式。

JavaScript 的全局作用域

JavaScript 的作用域从全局作用域开始为节点,形成了一个嵌套的树形结构。 仅仅在浏览器里直接使用 <script> 标签时的代码直接运行在全局作用域中。在这当中有两种全局变量:

全局对象能够通过 globalThis 访问到。下面的 HTML 代码示范了 globalThis 和几种不同的全局变量。

<script>
const one = 1;
var two = 2;
</script>
<script>
// 所有的 script 标签中都共享同一个顶层作用域
console.log(one); // 1
console.log(two); // 2
// 不是所有的声明都在全局对象上创建了属性
console.log(globalThis.one); // undefined
console.log(globalThis.two); // 2
</script>

应注意的是,每一个模块都有自己的作用域。因此,在模块中的顶层作用域的变量不是全局的。下图展示了不同作用域之间的关系。

this 的值

无论何时调用方法的对象中, this 的值都取决于当前的作用域:

如果你间接的调用 eval(),它将会随意的在全局作用域中执行。因此,你能用下面的代码来获取全局的 this

const theGlobalThis = eval.call(undefined, this);

需要警告的是,如果你使用了 CSP (Content Security Policy), eval, new Function() 等方法是无法生效的。这就使得这种获取全局对象的方法在一些情况下是不合适的。

globalThis 和其他(window 等等)

globalThis 是一个全新的标准方法用来获取全局 this 。之前开发者会通过如下的一些方法获取:

新提案也规定了,Object.prototype 必须在全局对象的原型链中。下面的代码在现在的最新浏览器中已经会返回 true 了:

Object.prototype.isPrototypeOf(globalThis); // true

globalThis 使用实例

由于需要向下兼容,全局对象现在已经被认为是一个 JavaScript 无法摆脱的错误了。它会造成负面的性能影响并且令人产生困惑。

ECMAScript 介绍了一些方法来让你更简单的避免触碰全局对象 - 例如:

因此,这有几个使用 globalThis 相关的场景 - 例如:

polyfill

此提案的作者 Jordan Harband 写过一个 globalThis 的 polyfill。 用 CommonJS 语法引入:

// 生成 `global` 变量的值
var global = require('globalthis')();
// 垫片 `global` (全局安装)
require('globalthis/shim')();

用 ES6 模块语法引入:

// 生成 `global` 变量的值
import getGlobal from 'globalthis';
const global = getGlobal();
// 垫片 `global` (全局安装)
import shim from 'globalthis/shim'; shim();

这个包总是会使用“最原生”的方法来访问全局对象(在 Node.js 中是 global,在浏览器中是 window 等等)

得到一个全局对象的引用

在内部实现中 polyfill 使用 getPolyfill() 来得到全局对象。下面是实现方法:

// polyfill.js
var implementation = require('./implementation');
module.exports = function getPolyfill() {
if (typeof global !== 'object' || !global
|| global.Math !== Math || global.Array !== Array) {
return implementation;
}
return global;
};
// implementation.js
if (typeof self !== 'undefined') {
module.exports = self;
} else if (typeof window !== 'undefined') {
module.exports = window;
} else if (typeof global !== 'undefined') {
module.exports = global;
} else {
module.exports = Function('return this')();
}

FAQ: globalThis

为什么不在所有地方都使用 global、self 或 window?

唉,这是不可能的,因为许多 JavaScript 库使用这些变量来检测代码运行在哪一个平台上。

globalThis 有考虑使用过其他名字吗?

这个 issue列出了我们考虑过的所有命名以及没有采用的原因。

资源与背景资料

General background:

Specifications:

著作权声明

本文译自 ES proposal: globalThis
译者 郭梓梁,首次发布于 MeloGuo Blog,转载请保留以上链接


GitHub · guoziliang199606@gmail.com · 微信
CC BY-NC 4.0 © Melo Guo.RSS