为什么 await 和 async 是有效的变量名?
Why are await and async valid variable names?
我正在试验 /
在不同关键字和运算符周围的解释方式,发现以下语法是完全合法的:
// awaiting something that isn't a Promise is fine, it's just strange to do:
const foo = await /barbaz/
myFn()
错误:
Uncaught ReferenceError: await is not defined
它似乎试图将 await
解析为 变量名 ..?我在期待
await is only valid in async function
或者类似
Unexpected token await
令我震惊的是,你甚至可以给它赋值:
const await = 'Wait, this actually works?';
console.log(await);
不应该像 let
、finally
、break
等那样明显地导致语法错误吗?为什么允许这样做,第一个片段中到底发生了什么?
保留关键字不能用作identifiers (variable names)。与大多数其他特殊 Javascript 单词(如问题中列出的单词 let
、finally
、...)不同,await
是 而不是 保留关键字,因此将其用作变量名不会引发 SyntaxError。为什么新语法出来的时候没有把它做成保留关键字?
向后兼容性
回到 2011 年,当 ES5 还是一个相对较新的东西时,使用 await
(和 async
)作为变量名的代码是完全有效的,所以你可能已经在几个网站:
function timeout(ms) {
var await = $.Deferred();
setTimeout(await.resolve, ms);
return await.promise();
};
这个变量名的选择可能看起来很奇怪,但是没有错。 await
和 async
从来都不是保留关键字——如果 ES2017 规范的作者将 await
设为保留关键字,并且浏览器实现了该更改,那么人们在较新的浏览器上访问这些旧网站时会无法使用这些网站;他们很可能会坏掉。
因此,如果将它们设为保留关键字,少数 个选择特殊变量名称的网站将无法正常工作 - 为什么这些网站的存在会永久影响ECMAscript 的未来发展并导致像问题中那样令人困惑的代码?
因为浏览器会拒绝实现破坏现有网站的功能。如果用户发现某个网站无法在一种浏览器上运行,但在另一种浏览器上运行,这将激励他们切换浏览器——第一个浏览器的制造商不希望这样,因为这对他们来说意味着更少的市场份额,即使这是一个使语言更一致和更容易理解的特性。此外,规范的编辑者不想添加永远不会实现(或只会偶尔实现)的内容,因为那样规范将失去其作为标准的某些地位——与其主要目标背道而驰。
您可以通过 Array.prototype.flatten
and Array.prototype.contains
- when browsers started shipping them, it was found that they broke a few existing sites due to name conflicts, so the browsers backed out of the implementation, and the specification had to be tweaked (the methods were renamed to .flat
and .includes
) 看到这些互动。
其实是一种情况await
不能作为标识符,在ES6模块内部:
<script type="module">
const await = 'Does it work?';
</script>
这是因为在研究 ES6 (ES2015) 模块时,async
/await
已经在 horizon 上(initial commit for the async
/await
proposal 可以在2014 年初),因此在设计模块时,可以将 await
设为保留关键字,为将来做准备,而不会破坏任何现有站点。
关于问题中的第一个片段:
const foo = await /barbaz/
myFn()
这在语法上是有效的,因为 await
是 async
函数之外的有效变量名,并且解释器认为您正在尝试 划分 ,而不是使用正则表达式:
const foo = await / barbaz / myFn()
不依赖自动分号插入会更早地发现问题,因为最后一个 /
不能被解释为除法:
const foo = await /barbaz/;
myFn();
这种确切的 somewhat-ambiguous 情况实际上是在 async
/await
的 TC39 meeting 中专门提出的:
YK: What are you worried about?
WH: Ambiguities on code sequences that start with await/ and then get interpreted in diverging ways (due to the await-as-identifier vs await-as-operator distinction that flips the / between division and starting a regexp) by cover grammars vs. real grammars. It's a potential bug farm.
我正在试验 /
在不同关键字和运算符周围的解释方式,发现以下语法是完全合法的:
// awaiting something that isn't a Promise is fine, it's just strange to do:
const foo = await /barbaz/
myFn()
错误:
Uncaught ReferenceError: await is not defined
它似乎试图将 await
解析为 变量名 ..?我在期待
await is only valid in async function
或者类似
Unexpected token await
令我震惊的是,你甚至可以给它赋值:
const await = 'Wait, this actually works?';
console.log(await);
不应该像 let
、finally
、break
等那样明显地导致语法错误吗?为什么允许这样做,第一个片段中到底发生了什么?
保留关键字不能用作identifiers (variable names)。与大多数其他特殊 Javascript 单词(如问题中列出的单词 let
、finally
、...)不同,await
是 而不是 保留关键字,因此将其用作变量名不会引发 SyntaxError。为什么新语法出来的时候没有把它做成保留关键字?
向后兼容性
回到 2011 年,当 ES5 还是一个相对较新的东西时,使用 await
(和 async
)作为变量名的代码是完全有效的,所以你可能已经在几个网站:
function timeout(ms) {
var await = $.Deferred();
setTimeout(await.resolve, ms);
return await.promise();
};
这个变量名的选择可能看起来很奇怪,但是没有错。 await
和 async
从来都不是保留关键字——如果 ES2017 规范的作者将 await
设为保留关键字,并且浏览器实现了该更改,那么人们在较新的浏览器上访问这些旧网站时会无法使用这些网站;他们很可能会坏掉。
因此,如果将它们设为保留关键字,少数 个选择特殊变量名称的网站将无法正常工作 - 为什么这些网站的存在会永久影响ECMAscript 的未来发展并导致像问题中那样令人困惑的代码?
因为浏览器会拒绝实现破坏现有网站的功能。如果用户发现某个网站无法在一种浏览器上运行,但在另一种浏览器上运行,这将激励他们切换浏览器——第一个浏览器的制造商不希望这样,因为这对他们来说意味着更少的市场份额,即使这是一个使语言更一致和更容易理解的特性。此外,规范的编辑者不想添加永远不会实现(或只会偶尔实现)的内容,因为那样规范将失去其作为标准的某些地位——与其主要目标背道而驰。
您可以通过 Array.prototype.flatten
and Array.prototype.contains
- when browsers started shipping them, it was found that they broke a few existing sites due to name conflicts, so the browsers backed out of the implementation, and the specification had to be tweaked (the methods were renamed to .flat
and .includes
) 看到这些互动。
其实是一种情况await
不能作为标识符,在ES6模块内部:
<script type="module">
const await = 'Does it work?';
</script>
这是因为在研究 ES6 (ES2015) 模块时,async
/await
已经在 horizon 上(initial commit for the async
/await
proposal 可以在2014 年初),因此在设计模块时,可以将 await
设为保留关键字,为将来做准备,而不会破坏任何现有站点。
关于问题中的第一个片段:
const foo = await /barbaz/
myFn()
这在语法上是有效的,因为 await
是 async
函数之外的有效变量名,并且解释器认为您正在尝试 划分 ,而不是使用正则表达式:
const foo = await / barbaz / myFn()
不依赖自动分号插入会更早地发现问题,因为最后一个 /
不能被解释为除法:
const foo = await /barbaz/;
myFn();
这种确切的 somewhat-ambiguous 情况实际上是在 async
/await
的 TC39 meeting 中专门提出的:
YK: What are you worried about?
WH: Ambiguities on code sequences that start with await/ and then get interpreted in diverging ways (due to the await-as-identifier vs await-as-operator distinction that flips the / between division and starting a regexp) by cover grammars vs. real grammars. It's a potential bug farm.