一元运算符"++"和" - "奇怪的情况

And*_*iga 25 javascript unary-operator

这是使用一元运算符"++"的测试情况:

var j = 0 ;
console.log(j);
j = j++;
console.log(j);
Run Code Online (Sandbox Code Playgroud)

为此,输出为:

0
0
Run Code Online (Sandbox Code Playgroud)

由于++运算符的位置位于操作数的后面,因此它的优先级低于赋值的优先级,我希望"j"首先接收自身的值(ie0),然后递增.那么为什么第二个console.log(j)电话仍然显示为"0"?

为了清楚起见,我知道解决方案是:

// 1)
j++;
// 2)
++j;
// 3)
j += 1;
// 4)
j = ++j;
Run Code Online (Sandbox Code Playgroud)

但我需要知道为什么在这个特定情况下不进行增量步骤,而不是如何解决它!

Lig*_*ica 52

使用后增量时,这是一种不直观(但不是"怪异"!)的行为.

声明j = j++是这样做的:

  1. 评估LHS
    • 在这种情况下,没有什么特别的事情发生,因为你只是命名一个变量,但情况可能并非总是如此,例如 foo() = j++
  2. 评估RHS
    • 取当前值j(0),并记住它作为结果;
    • 增量j(获得1);
  3. 将RHS分配给LHS
    • 回想一下,RHS评估的是"记住"值j(0).

结果是无操作.

这里的关键是在最终分配之前评估整个RHS并执行后增量.


http://www.ecma-international.org/ecma-262/5.1/#sec-11.3.1
http://www.ecma-international.org/ecma-262/5.1/#sec-11.13.1

  • 注意,如果左手侧本身具有副作用,则在评估右手侧之前*发生该副作用. (6认同)
  • @AndreiOniga:`j`在_both_个案中得到递增的值; 但是,在方案#1中,您随后会立即重新分配原始值.回想一下`var j = 0; 警报(J ++); alert(j);`弹出`0`然后是'1`,而不是`1`然后是`1`. (3认同)
  • 请注意,有些人使用"no-op"来描述没有执行实际工作的汇编语言构造(也称为"NOP").我完全同意这是_effectively_一个无操作,它实际上并不是汇编语言意义上的"无操作".(除非你的编译器超级智能并优化.... :-) (2认同)

the*_*eye 10

根据ECMA后缀增量运算符规范,

  1. 让lhs成为评估LeftHandSideExpression的结果.
  2. 如果满足以下条件,则抛出SyntaxError异常:
    1. 类型(lhs)是引用是真的
    2. IsStrictReference(lhs)是真的
    3. Type(GetBase(lhs))是环境记录
    4. GetReferencedName(lhs)是"eval"或"arguments"
  3. 让oldValue为ToNumber(GetValue(lhs)).
  4. 设newval是将值1添加到oldValue的结果,使用与+运算符相同的规则(见11.6.3).
  5. 调用PutValue(lhs,newValue).
  6. 返回oldValue.

因此,很明显,新值首先在lhs(在这种情况下j)设置,并且旧值作为表达式的结果返回,该值又被重新设置j.所以,价值不会改变.