在Node.js的REPL中(也在SpiderMonkey中测试)序列
foo
有效,"bar"
后来等于null
而不是bar
。
这似乎违反直觉,因为人们会认为括号至少会取消引用(foo, bar) = 4
(true ? bar : foo) = 4
并在赋值中抛出无效的左侧。
可以理解的是,当你做任何有趣的事情时,它会以上述方式失败。
@RELATION points
@ATTRIBUTE x REAL
@ATTRIBUTE y REAL
@ATTRIBUTE id STRING
@DATA
1,5,100
2,6,200
3,5,300
根据ECMA-262 on LeftHandExpressions(据我可以解释),没有有效的非终端会导致括号被接受。
有没有我没见过的东西?
答案 0 :(得分:28)
确实有效。您可以在括号中包装任何简单的赋值目标。
正确识别后,=
操作的左侧部分为LeftHandSideExpression
。这可以通过各种优先级(NewExpression
,MemberExpression
)跟踪到PrimaryExpression
,而后者可能是CoverParenthesizedExpressionAndArrowParameterList
:
( Expression[In, ?Yield] )
(实际上,在使用目标PrimaryExpression
解析时,它是ParenthesizedExpression
)。
至少,语法是有效的。它是否真正有效的JS语法是由另一个因素决定的:早期错误静态语义。这些基本上是散文或算法规则,在某些情况下使某些生产扩展无效(语法错误)。例如,这允许作者重用数组和对象初始化语法进行解构,但仅应用某些规则。在我们找到的early errors for assignment expressions
如果 LeftHandSideExpression 既不是 ObjectLiteral 也不是 ArrayLiteral 且 IsValidSimpleAssignmentTarget Reference Error LeftHandSideExpression 的>是
false
。
我们也可以在evaluation of assignment expressions中看到这种区别,其中简单的赋值目标被评估为可以赋值的引用,而不是像对象和数组文字一样获得解构模式。
那么IsValidSimpleAssignmentTarget对 LeftHandSideExpressions 做了什么?基本上,它允许分配属性访问,并禁止分配调用表达式。它没有说明具有own IsValidSimpleAssignmentTarget rule的普通 PrimaryExpressions 的任何内容。它只是通过CoveredParenthesizedExpression operation在括号之间提取 Expression ,然后再次检查它的IsValidSimpleAssignmentTarget。简而言之:(…) = …
在… = …
有效时有效。它仅为Identifiers(例如您的示例)和属性提供true
。
答案 1 :(得分:15)
根据@dlatikay's suggestion,按照现有的预感,对CoveredParenthesizedExpression
的研究可以更好地了解这里发生的事情。
显然,在spec中找不到非终端的原因,解释为什么(foo)
可以作为LeftHandExpression
被接受,这简直太简单了。我假设您了解解析器的工作原理,并且它们分两个阶段运行: Lexing 和解析。
我从这个小小的研究中得到的结论是,构造(foo)
在技术上并没有被提供给解析器,因此你可能会想到引擎。
var foo = (((bar)));
众所周知,这样的事情是完全合法的。为什么?那么你在视觉上可以只是忽略括号,而声明仍然是完全合理的。
同样,这是另一个有效的例子,即使从人类可读性的角度来看,因为括号只能说明PEMDAS已经隐含的内容。
(3 + ((4 * 5) / 2)) === 3 + 4 * 5 / 2
>> true
在理解解析器已经如何工作的情况下,可以从中松散地得出一个关键的观察结果。 (记住,Javascript仍然被解析(read: compiled)和然后运行)所以从直接意义上说,这些括号是"说明显而易见的"
基本上,括号(函数参数除外)会折叠为其包含符号的正确分组。 IANAL,但是,在非专业人士的术语中,这意味着括号仅被解释为指导解析器如何对其读取的内容进行分组。如果括号的上下文已经按顺序"并且因此不需要对发出的AST进行任何调整,则发出(机器)代码,好像这些括号不存在于所有。
解析器或多或少是懒惰的,假设parens是不礼貌的。 (在这种边缘情况下,不是真的)
根据规范中的12.2.1.5 Static Semantics: IsValidSimpleAssignmentTarget,
PrimaryExpression:(CoverParenthesizedExpressionAndArrowParameterList)
- 让expr成为CoverParenthesizedExpressionAndArrowParameterList的CoveredParenthesizedExpression。
- 返回expr的IsValidSimpleAssignmentTarget。
醇>
即。如果期望primaryExpression
返回括号内的任何内容并使用它。
因此,在这种情况下,它不会将(foo)
转换为CoveredParenthesizedExpression{ inner: "foo" }
,而只是将其转换为foo
,这样可以保留Identifier
这一事实从语法上来说,虽然不一定是词汇,但是有效。
想要更多洞察力?