关于全局变量/全局命名空间的 JavaScript 策略

gma*_*man 6 javascript specifications language-lawyer

今天我遇到了top一个预先存在的全局变量的问题。

const left = 1;
const right = 2;
const top = 3;
const bottom = 4;
console.log(left, right, top, bottom);
Run Code Online (Sandbox Code Playgroud)

结果:

Uncaught SyntaxError: Identifier 'top' has already been declared
Run Code Online (Sandbox Code Playgroud)

我想我一直很幸运,直到今天我大部分时间top都在函数内部使用被调用的变量。

我有多少需要担心浏览器添加新的全局变量会在未来破坏代码?似乎直到 es6 import 几乎所有浏览器库都使用全局变量,除非它们有构建步骤。但是,看看这个top例子,浏览器似乎可以随时添加新的不可设置的全局变量,因此应该不惜一切代价避免它们。我看到一些诸如HTMLElement可分配之类的变量。

Uncaught SyntaxError: Identifier 'top' has already been declared
Run Code Online (Sandbox Code Playgroud)

结果:

function HTMLElement() { [native code] }
foo
Run Code Online (Sandbox Code Playgroud)

top一些遗留的东西,但浏览器规范承诺在未来不会做更多的事情吗?就像我不能分配window

console.log(HTMLElement);
HTMLElement = 'foo';
console.log(HTMLElement);
Run Code Online (Sandbox Code Playgroud)

结果:

SyntaxError: Identifier 'window' has already been declared
Run Code Online (Sandbox Code Playgroud)

但我可以process在节点中分配

Welcome to Node.js v12.6.0.
Type ".help" for more information.
> process
process {
  version: 'v12.6.0',
  versions: {
    node: '12.6.0',
 ...
}
> process = 'foo'
'foo'
> process
'foo'
> 
Run Code Online (Sandbox Code Playgroud)

sne*_*nek 2

我需要担心浏览器添加新的全局变量会在将来破坏代码吗?

你不应该担心它。JS 和 HTML 的新功能经过了广泛的测试。浏览器通常会部署代码来监视与计划的 API 的不兼容性,以确定它们是否可以安全发布。(例如,如果浏览器想要添加globalThis.foo,它可能会部署一个计数器,每次代码访问或分配时都会递增计数器,以globalThis.foo了解它是否已被用于其他用途)。此外,浏览器的开发者预览版使开发者能够在问题走得太远之前发现可能的问题。您可能会发现这很有趣:https ://developers.google.com/web/updates/2018/03/smooshgate 。

话虽如此,我仍然不建议您创建大量全局变量,这不是最美妙的模式。

top 是一些遗留的东西,但浏览器规范承诺将来不会做更多的事情吗?就像我无法分配窗口一样

这确实是遗产,尽管我不知道有任何这样的承诺。HTML 标准定义window.top如下(来自https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-window-object):

[LegacyUnforgeable] readonly attribute WindowProxy? top;
Run Code Online (Sandbox Code Playgroud)

[LegacyUnforgeable]表示该属性top是在windowproperty 属性configurable设置为 的情况下创建的false。隐藏不可配置属性的全局声明将失败,因为它们无法更改值。

但我可以在节点中分配进程

这是因为process在 Node.js 中是一个可配置的属性。

> Object.getOwnPropertyDescriptor(globalThis, 'process')
{
  get: [Function: get],
  set: [Function: set],
  enumerable: false,
  configurable: true
}
Run Code Online (Sandbox Code Playgroud)

最后要注意的是,赋值和声明之间存在差异。您仍然可以分配给不可配置的属性,只要它们可写或提供设置器即可。