【问题标题】:Why a || a = 'bar' will get a reference error in javascript?为什么是 || a = 'bar' 会在 javascript 中出现引用错误?
【发布时间】:2020-02-18 06:28:46
【问题描述】:

代码sn-p是:

var a = 'foo'
a || a = 'bar'

我的预期是它可以正常工作,这意味着a最终将是'bar'。但是我遇到了错误

Uncaught SyntaxError: Invalid left-hand side in assignment.

根据报错,我想可能是左边的表达式a || a有问题。看来a || a在这里无效。但是为什么呢?我求助于ecmascript language specification。在12.15.1 静态语义:早期错误,我发现:

如果 LeftHandSideExpression 既不是 ObjectLiteral 也不是 ArrayLiteral 且 LeftHandSideExpression 的 AssignmentTargetType 无效,则为早期参考错误。

所以,LeftHandSideExpression a||a 的AssignmentTargetType 是无效的。但是我很困惑为什么a||a 的AssignmentTargetType 是无效的。关于这个,规范刚刚说:

12.15.3 静态语义:AssignmentTargetType

赋值表达式:

产量表达式

箭头函数

异步箭头函数

LeftHandSideExpression = 赋值表达式

LeftHandSideExpressionAssignmentOperatorAssignmentExpression

  1. 返回无效。

根据给定的内容,我无法弄清楚为什么 a||a 的 AssignmentTargetType 无效。

我的问题是:为什么a||a = 'bar'会在javascript中出现引用错误?如果是LeftHandSideExpression的AssignmentTargetType无效,为什么a||a无效?

【问题讨论】:

  • = 的左侧必须是单个标识符,或有效的解构目标
  • 你希望表达式做什么?
  • @Teemu a 将成为“酒吧”
  • @Chor 有趣。 a 的值是 "foo",逻辑 OR 返回其操作数之一的值,在这种情况下,我希望 "foo" = "bar",这没有多大意义..?

标签: javascript ecmascript-6


【解决方案1】:

我的问题是:为什么a||a = 'bar' 会在 javascript 中出现引用错误?

这不是参考错误,而是语法错误。这意味着您编写的代码无法解析为有效的程序。

如果是LeftHandSideExpression的AssignmentTargetType无效,为什么a||a无效?

比这简单得多:赋值表达式的语法,除其他外,是

LeftHandSideExpression = AssignmentExpression

这意味着在= 的左侧我们需要一个LeftHandSideExpression

||LogicalORExpression 但不是 LeftHandSideExpression,因此它不能出现在这个位置。

您可以考虑按层次结构组织不同类型的表达式(我通过省略某些类型的表达式来简化以下示例):

AssignmentExpression
         ^
         |
LogicalORExpression
         ^
         |
LeftHandSideExpression
         ^
         |
PrimaryExpression
         ^
         |
Identifier Reference

即:一个标识符引用是一个PrimaryExpression是一个LeftHandSideExpression,等等

LogicalORExpression 在层次结构中较高,这使其成为包含LeftHandSideExpression 的超集。这意味着有一些表达式,例如||,它们是LogicalORExpression,但不是LeftHandSideExpression

【讨论】:

  • 我不明白LeftHandSideExpression 怎么可能是LogicalORExpression 而不是反过来?
  • @LeonSegal:也许我没有表达清楚:因为LogicalORExpression 是包含LeftHandSideExpression 的超集,所以一些LogicalORExpressionLeftHandSideExpression,但不是全部。 || 就是其中之一。我更新了措辞。
  • 我想我还是很困惑。 LogicalORExpression 包含在 LeftHandSideExpression 中,但也不能在左侧表达式中使用 or 语句?
  • @LeonSegal: 不,LogicalORExpression 不包含在 LeftHandSideExpression 中,反之亦然。
  • 这仍然让我感到困惑 - LeftHandSideExpression 包含在 LogicalORExpression 中,所以 LeftHandSideExpressionLogicalORExpression 但你实际上不能在左手表达式中使用 or 语句,即使左手表达式是 or 语句?我将不得不学习如何阅读我认为的规范。
【解决方案2】:

JavaScript 将从左到右执行。 a || a 将评估为 foo 在您尝试将新值重新分配给 a 之前。这意味着您正在尝试运行 'foo' = 'bar',这会导致您出现无效的左手分配错误。

【讨论】:

  • 是这样吗?我以为||在 js 中,如果第一个操作数为真,则计算第一个操作数,如果第一个操作数为假,则计算第二个操作数?因此,即在这种情况下为“foo”。这不会使语句 'foo' = 'bar' 出错,因为字符串是不可变的?
  • 按照你说的,undefined || indefined = 'bar'也会变成undefined = 'bar',对吧?所以前者的结果和后者是一样的。但实际上,前者会得到一个错误,而后者的分配将成功并且不会出现任何错误。
  • @LeonSegal 我把 foo 的引号去掉了,所以我编辑了更新。我们在说同样的话。它永远不会超过第一个操作数并评估为'foo' = 'bar'
  • @Chor 不,这是不正确的 - undefined 是一个假值,不会传递第一个操作数
  • @shapirowned 即使在这种情况下,undefined || undefined 仍然会返回undefined。所以undefined || indefined = 'bar' 也会变成undefined = 'bar'
【解决方案3】:

更新:正如@Teemu 指出的那样。更新了 cmets。

var a = 'foo'
a || a = 'bar' // a || a evaluates to 'foo', So it will be `'foo' = 'bar'` here

a || (a = 'bar') // will result to a is 'foo'

a = ''
a || (a = 'bar') // will result to a is 'bar'

【讨论】:

  • 哦,我的错。你是对的@Teemu。感谢指正
猜你喜欢
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-10
  • 1970-01-01
  • 2018-06-03
  • 2016-06-10
相关资源
最近更新 更多