【问题标题】:What's a valid left-hand-side expression in JavaScript grammar?JavaScript 语法中有效的左侧表达式是什么?
【发布时间】:2011-04-12 05:05:24
【问题描述】:

好的,我们都知道有效的左侧表达式是什么。有点。*

但是,看the ECMA-Script standard的定义,我很困惑:

LeftHandSideExpression :
    NewExpression
    CallExpression

这只是定义中的错误,还是我这里有什么问题?我的意思是,这不是真的意思吗

new Object = 1; // NewExpression AssignmentOperator PrimaryExpression
function () { return foo; }() = 1;// CallExpression AssignmentOperator PrimaryExpression

应该是有效的赋值表达式吗?


* 根据我的拙见,这会更有意义:

LeftHandSideExpression :
    Identifier
    MemberExpression [ Expression ]
    MemberExpression . IdentifierName
    CallExpression [ Expression ]
    CallExpression . IdentifierName

【问题讨论】:

  • 如果您将函数调用括在括号中,您的第二个示例将起作用:(function () { return window; }()).x = 1
  • @Daniel:对,我更新了示例
  • @user123444555621 您对LeftHandSideExpression 的(理解)定义缺少分组运算符( LeftHandSideExpression )

标签: javascript grammar ecma262


【解决方案1】:

这是另一种 JavaScript 语法,它只匹配有效的 LeftHandSideExpressions,即实际可分配的 LeftHandSideExpressions。

NewExpression :
    PrimaryExpression
    new NewExpressionQualifier Arguments
    new NewExpressionQualifier

NewExpressionQualifier :
    NewExpressionQualifier Qualifier
    NewExpression

CallExpression :
    NewExpression
    CallExpressionQualifier Arguments

CallExpressionQualifier :
    CallExpression
    CallExpressionQualifier Qualifier

LeftHandSideExpression :
    LeftHandSideExpression Qualifier
    CallExpression Qualifier
    Identifier
    ( LeftHandSideExpression )
    ( Expression , LeftHandSideExpression )

Qualifier :
    . IdentifierName
    [ Expression ]

关联的 new 或 call 表达式的选择不明确的每个 Arguments 应与最近的可能的 new 表达式相关联,否则将没有相应的 Arguments。我认为这是 JavaScript 语法中同时存在 NewExpression 和 MemberExpression 非终结符的原因之一。

【讨论】:

  • 根据您对LeftHandSideExpression 的定义,我得出结论,(a = 1, b) 将是可分配的LeftHandSideExpression。但是,在分配 (a = 1, b) = 2 中使用它会导致 Uncaught ReferenceError: Invalid left-hand side in assignment
  • 逗号运算符不是左侧表达式,因为它不返回引用 (4. Return GetValue(rref))。但是,它可能包含一个简单的赋值表达式作为右操作数。 a = 1, b = 2 可以归为(a = 1) , (b = 2),但(a = 1, b) = 2 会导致GetValue(b) = 2
【解决方案2】:

为了简明扼要地回答您的问题,LeftHandSideExpression 产品下的所有内容都是有效的LeftHandSideExpression


我认为你真正要问的问题是:

什么是有效的LeftHandSideExpression 并且可以赋值?

这个问题的答案是任何可以解析为 Reference 的东西,这是规范中定义明确的概念。在你的例子中

new Object = 1;

new Object 是有效的 LeftHandSideExpression,但它不能解析为 Reference

(new Object).x = 1;

左侧是MemberExpression . IdentifierName,根据规范,最后一步是:

返回引用类型的值 ...


如果您将其视为 2 个独立的属性,则更有意义。

  1. 它是有效的 LeftHandSideExpression 吗?
  2. 它是一个有效的参考吗?

属性 1 在句法分析阶段确定,属性 2 在语义分析阶段确定。查看 8.7.2 PutValue (V, W) 了解更多详情。

这是规范本身的完整解释:

8.7 参考规范类型

引用类型用于解释删除、typeof 和赋值运算符等运算符的行为。例如,赋值的左侧操作数预计会产生引用。相反,赋值行为可以完全根据赋值运算符左侧操作数的句法形式的案例分析来解释,但有一个困难:允许函数调用返回引用。这种可能性纯粹是为了宿主对象而被承认的。本规范定义的内置 ECMAScript 函数没有返回引用,也没有规定用户定义的函数返回引用。 (不使用句法案例分析的另一个原因是它冗长而笨拙,会影响规范的许多部分。)


看了你的建议后,我相信它会抛弃某些有效的表达方式(注意:我不宽恕这个。)

function OuterObj() {
    this.Name = "Outer";
    this.InnerObj = function() {
        this.Name = "Inner";
    }
}

var obj; (obj = new new OuterObj().InnerObj).Name = "Assigned";

这是NewExpression很重要的情况

【讨论】:

  • 是的。我一直认为阶段 2 是在运行时执行的,而阶段 1 是在解析时执行的。因此,if (false) { new Object = 1; } 不应该是语法错误,并且在 Safari 中确实有效。看了一下 Firefox 源代码,我找到了this:Firefox 把这个当作一个特例。 (有趣的事实:错误代码被称为JSMSG_BAD_LEFTSIDE_OF_ASS
  • @Pumbaa80 - 我认为在动态语言中这样做真的很有意义。
  • 为什么规范将生产 ClassHeritage 设置为“扩展”LeftHandSideExpression?不应该是 BindingIdentifier 吗?我发现这非常复杂。想象一个类定义,如 class X extends (new Y) 或 class X extends (function() {})!世界上谁会需要这样的功能?事实上,Firefox 甚至指责第一种情况无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-08
  • 2012-03-22
  • 2016-11-24
  • 1970-01-01
  • 2012-02-24
相关资源
最近更新 更多