当您尝试这样做时:
var b1, b2;
b1 = !b2 = true;
document.write(b1, " ", b2);
因为它们在功能上是等效的‡你基本上是在做:
var b1, b2;
!b2 = true;
b1 = true; //just the value of b2, not b2 itself
document.write(b1, " ", b2);
在!b2 = true 行中,您正试图将计算结果为一个值(左侧)的表达式分配给一个值——这绝对没有意义。这样想:
-
!b2 被分配给 true。 !b2 是一个表达式,被评估为一个布尔 值,而不是变量。
- 这类似于
1 + 1 = 2。由于1 + 1 被评估为一个值,因此您不能将它分配给另一个值2。您必须为 variable 赋值,因为值到值的赋值在语义和逻辑上都是无效的。
- 考虑上述问题的另一种方法是实现这一点:
1 + 1 是一个值。 2 是一个值。您不能将值分配给值,因为该值已经具有值。 2 等常量的值为 2,不能更改。如果我们尝试1 - 1 = 2 会怎样? 0,一个常量和值,不能是2,因为它是一个常量。
因此,将一个值赋给一个值在语义上和逻辑上都是无效的。您不能将0 分配给2,就像您不能将false 分配给true。
如果您想更好地理解语法和语义,以及为什么会抛出 ReferenceError,您可以深入研究 ECMAScript® 2015 Language Specification†。根据规范:
Section 12.14.1 - 赋值运算符 - 静态语义:早期错误
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
- 如果
LeftHandSideExpression 既不是 ObjectLiteral 也不是 ArrayLiteral 和 @987654354,这是一个早期的 Reference 错误LeftHandSideExpression 的@ 是假的。
IsValidSimpleAssignmentTarget 在哪里:
Section 12.14.3 - 赋值运算符 - 静态语义:IsValidSimpleAssignmentTarget
AssignmentExpression :
YieldExpression
ArrowFunction
LeftHandSideExpression = AssignmentExpression
LeftHandSideExpression AssignmentOperator AssignmentExpression
1。返回 false。
现在回头看看你的代码:b1 = !b2 = true。 b1 = !b2 很好,因为它是 LeftHandSideExpression = AssignmentExpression,因此对于 IsValidSimpleAssignmentTarget 返回 true。当我们检查!b2 = true 时,问题就出现了。如果我们看LeftHandSideExpression的定义:
Section 12.3 - 左侧表达式
语法
LeftHandSideExpression :
NewExpression
CallExpression
(您可以在上面的规范链接中查看NewExpression和CallExpression的定义)
您可以看到!b2 = true 不是有效的AssignmentExpression,因为它不符合条件LeftHandSideExpression = AssignmentExpression。这是因为!b2 不是有效的LeftHandSideExpression,也不是ObjectLiteral 也不是ArrayLiteral,因此IsValidSimpleAssignmentTarget返回 false,抛出 ReferenceError。请注意,错误是early error,这意味着它在执行任何代码之前被抛出,如@Bergi's comment 中所述。
您可以通过执行以下任一操作来解决此问题,具体取决于您想要的结果:
b1 = !(b2 = true);
使用括号,括号内优先于括号外。这样,b2 被赋值,因为它是true,括号内的计算结果为true。接下来就相当于:
b1 = !(true);
如上所述,括号内的计算结果为true。 b1 将与预期的 b2 相反,b2 将是 true。
如果您希望 b1 成为 true 和 b2 成为 false,请像这样重组语句:
b2 = !(b1 = true);
这样一来,与上面的完全相反,给出b1 = true和b2 = false。
‡正如@Bergi 在 cmets 中提到的,b1 被分配了正确的操作数,在这种情况下为 true,而不是 !b2。
†虽然目前大多数浏览器不支持 ECMAScript 6 (2015) 的所有功能,而是使用ECMAScript 5.1 (2011),但两个版本的规范是相同的。所有定义都相同,因此解释仍然有效。