繁体   English   中英

为什么`(foo)=“bar”在JavaScript中合法?

[英]Why is `(foo) = “bar”` legal in JavaScript?

在Node.js的REPL中(也在SpiderMonkey中测试)序列

var foo = null;
(foo) = "bar";

是有效的, foo随后等于"bar"而不是null

这似乎违反直觉,因为人们会认为括号至少会取消引用bar在赋值中抛出无效的左侧

可以理解的是,当你做任何有趣的事情时,它确实以上述方式失败了。

(foo, bar) = 4
(true ? bar : foo) = 4

根据ECMA-262关于LeftHandExpressions (据我可以解释),没有有效的非终端会导致括号被接受。

有什么我没看到的吗?

它确实有效。 您可以在括号中包装任何简单的赋值目标。

正确识别后, = operation的左手部分是LeftHandSideExpression 这可以通过各种precendence水平(被跟踪NewExpressionMemberExpression )到PrimaryExpression ,这反过来又可能是一个CoverParenthesizedExpressionAndArrowParameterList

( [In, ?Yield] )

(实际上,当使用目标PrimaryExpression进行解析时,它是一个ParenthesizedExpression )。

所以它至少在语法上是有效的。 它是否真正有效的JS语法是由另一个因素决定的:早期错误静态语义。 这些基本上是散文或算法规则,在某些情况下使某些生产扩展无效(语法错误)。 例如,这允许作者重用数组和对象初始化语法进行解构,但仅应用某些规则。 在我们发现的赋值表达式早期错误中

如果LeftHandSideExpression既不是ObjectLiteral也不是ArrayLiteral并且LeftHandSideExpression的 IsValidSimpleAssignmentTargetfalse ,则它是早期的Reference Error

我们还可以在赋值表达式求值中看到这种区别,其中简单的赋值目标被计算为可以赋值的引用,而不是获取像对象和数组文字这样的解构模式。

那么IsValidSimpleAssignmentTargetLeftHandSideExpressions做了什么? 基本上,它允许分配属性访问,并禁止分配调用表达式。 它没有说明具有自己的IsValidSimpleAssignmentTarget规则的普通PrimaryExpressions的任何内容。 它所做的就是通过提取括号之间的表达 CoveredParenthesizedExpression操作 ,然后再次检查该IsValidSimpleAssignmentTarget。 简而言之: (…) = …… = …有效时有效。 它仅对标识符 (如您的示例)和属性产生true

根据@ dlatikay的建议 ,在现有的预感之后,对CoveredParenthesizedExpression研究使CoveredParenthesizedExpression更好地理解了这里发生的事情。

显然,在规范中找不到非终端的原因,解释为什么(foo)作为LeftHandExpression是可以接受的,这是非常简单的。 我假设您了解解析器的工作原理,并且它们分两个阶段运行: LexingParsing

我从这个小研究切片中学到的是,构造(foo)在技​​术上并没有被提供给解析器,因此你可能会想到引擎。

考虑以下

var foo = (((bar)));

众所周知,这样的事情是完全合法的。 为什么? 那么你在视觉上可以忽略括号,而声明仍然是完美的意义。

类似地,这是另一个有效的例子,即使从人类可读性的角度来看,因为括号只能说明PEMDAS已经隐含的内容。

(3 + ((4 * 5) / 2)) === 3 + 4 * 5 / 2
>> true

考虑到解析器已经如何工作,可以从中松散地得出一个关键的观察结果。 (记住,Javascript仍然被解析( 读取:编译然后运行)所以从直接意义上说,这些括号是“陈述明显的”

所有这一切,究竟是怎么回事?

基本上,括号(函数参数除外)将折叠为其包含符号的正确分组。 IANAL,但是,用非专业人的术语来说,这意味着括号仅被解释为指导解析器如何对其读取的内容进行分组。 如果括号的上下文已经“按顺序”,因此不需要对发出的AST进行任何调整,则发出(机器)代码,就好像这些括号根本不存在一样。

假设parens是无关紧要的,解析器或多或少是懒惰的。 (在这个边缘情况下,不是真的)

好的,这究竟发生在哪里?

根据12.2.1.5静态语义:规范中的IsValidSimpleAssignmentTarget

PrimaryExpression:(CoverParenthesizedExpressionAndArrowParameterList)

  1. 设expr为CoverParenthesizedExpressionAndArrowParameterList的CoveredParenthesizedExpression。
  2. 返回expr的IsValidSimpleAssignmentTarget。

IE如果期望primaryExpression返回括号内的任何内容并使用它。

因此,在这种情况下,它不会将(foo)转换为CoveredParenthesizedExpression{ inner: "foo" } ,它会将其简单地转换为foo ,这样可以保留它是一个Identifier的事实,从而在语法上, 但不一定是词法上有效的。

TL; DR

这是扫管笏。

想要更多洞察力?

查看@ Bergi的答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM