为什么 await 和 async 是有效的变量名?

IT技术 javascript async-await specifications language-design ecmascript-2017
2021-02-03 19:34:14

我正在尝试/在不同的关键字和运算符周围时如何解释,并发现以下语法是完全合法的:

// awaiting something that isn't a Promise is fine, it's just strange to do:
const foo = await /barbaz/
myFn()

错误:

未捕获的 ReferenceError:未定义等待

看起来它试图将 解析await变量名..?我期待

await 仅在异步函数中有效

或者像

意外的令牌等待

令我恐惧的是,您甚至可以为它分配一些东西:

const await = 'Wait, this actually works?';
console.log(await);

如若不是如此明显的错误原因语法错误,因为它确实有letfinallybreak,等?为什么这是允许的,第一个片段中到底发生了什么?

1个回答

保留关键字不能用作标识符(变量名)与大多数其他特殊的Javascript的话(像那些在这个问题列出letfinally...),await不是一个保留关键字,所以使用它作为一个变量名不抛出一个SyntaxError。为什么新语法出来的时候不把它做成保留关键字呢?

向后兼容

早在 2011 年,当 ES5 还是一个相对较新的东西时,使用await(and async) 作为变量名的代码是完全有效的,所以你可能在几个网站上看到过这样的事情:

function timeout(ms) {
  var await = $.Deferred();
  setTimeout(await.resolve, ms);
  return await.promise();
};

选择那个变量名可能看起来很奇怪,但它并没有await并且async从来没有被保留关键字——如果 ES2017 规范的作者await成为保留关键字,并且浏览器实现了这一改变,那么在新浏览器上访问那些旧站点的人将无法使用这些站点;他们很可能会被打破。

因此,也许如果将它们设置为保留关键字,一些选择特殊变量名称的站点将无法正常工作 - 为什么这些站点的存在会永久影响 ECMAscript 的未来演变并导致问题中的代码混乱?

因为浏览器将拒绝实现破坏现有站点的功能。如果用户发现某个网站无法在一个浏览器上运行,但在另一个浏览器上运行,这将激励他们切换浏览器——第一个浏览器的制造商不会想要这样,因为这意味着他们的市场份额会减少,即使这是一个使语言更加一致和易于理解的功能。此外,规范的编辑者不想添加永远不会实现(或只会偶尔实现)的东西,因为那样规范将失去其作为标准的某些地位——与其主要目标背道而驰。

您可以看到这些交互与Array.prototype.flattenArray.prototype.contains- 当浏览器开始发布它们时,发现它们由于名称冲突而破坏了一些现有站点,因此浏览器退出了实现,并且必须调整规范(方法被重命名为.flat.includes)。


实际上有其中的情况await不能被用作标识符,这是ES6module内:

<script type="module">
  const await = 'Does it work?';
</script>

这是因为当 ES6 (ES2015) module被弄清楚时,async/await已经在地平线上(可以在 2014 年初看到/提案的初始提交asyncawait),所以在设计module时,await可以将保留关键字设置为准备为未来,不破坏任何现有的网站。


关于问题中的第一个片段:

const foo = await /barbaz/
myFn()

这在语法上是有效的,因为它awaitasync函数之外的有效变量名,并且解释器认为您正在尝试,而不是使用正则表达式:

const foo = await / barbaz / myFn()

不依赖于自动分号插入会更早地发现问题,因为最后一个/不能被解释为除法:

const foo = await /barbaz/;
myFn();

这种有点模棱两可的情况实际上是/TC39 会议中特别提出的asyncawait

YK:你担心什么?

WH:以 await/ 开头的代码序列的歧义,然后以不同的方式解释(由于 await-as-identifier 与 await-as-operator 的区别,在除法和开始正则表达式之间翻转 /)覆盖语法 vs.真正的语法。这是一个潜在的错误农场。

今天自言自语.. 不,只是开玩笑的好帖子。在您做出回应之前,我最初的直觉反应是兼容性。我认为这也是为什么of,因为 infor of没有保留,尽管即使在module模式下这仍然有效。
2021-03-30 19:34:14
您认为向后兼容的假设是正确的。这就是为什么我们还必须async在函数声明站点添加关键字以将上下文从“await 是标识符”更改为“await 是关键字”的原因。出于完全相同的原因,我们有function*yield,它也是生成器之外的有效标识符名称。
2021-04-01 19:34:14