我想快速连续地使用运算符对几个变量做一些事情。我不认为我想做的事情本身很重要;我的问题更多是关于 JavaScript 评估的基础知识。
在下面的三个示例中,我尝试使用加法来更改两个变量的值。然而,并不是所有的都像我(也许是天真的)预期的那样表现。
作为三个单独的声明的操作
var a = 9, b = 2; a += b; b += a; a += b; // a === 24, b === 13
用逗号分隔的操作
var a = 9, b = 2; a += b, b += a, a += b; // AS EXPECTED: a === 24, b === 13
一个语句/表达式中的操作
var a = 9, b = 2; a += (b += (a += b)); // BUT HERE WE GET THIS: a === 22, b === 13
在最后一个示例中,b
按预期计算,但a
计算结果比前两个示例中出现的值少二。
我认为这是因为括号中的所有内容都返回正确的值,但最终添加到 的原始值a
,即9
,而不是(a += b)
前面优先级建议的值11
。
我已经在 Flanagan 的JavaScript: The Definitive Guide (6th ed.)中寻找了原因,(特别是在 4.11.1 “Assignment with operation”下)但在那里什么也没找到。Crockford 似乎也没有在The Good Parts中明确提及它。我使用了各种搜索词来尝试查找有关此行为的更多信息。谁能告诉我这种现象叫什么或指出有关此行为的一些信息(假设它是预期的)或我可能做错了什么(假设不是)?
注意。我意识到示例 3 中的括号可能是多余的,因为据我所知,赋值优先级无论如何都是从右到左的。但我认为让他们在那里会使这个例子更容易谈论。
更新
从下面的答案来看,我认为我对这个问题的困惑实际上源于从弗拉纳根的书中吸收了几段,可能是错误的:
在大多数情况下,表达式:
a op= b
其中op是一个运算符,等价于表达式:
a = a op b
在第一行,表达式
a
被计算一次。在第二个中,它被评估两次。仅当 sidea
包含诸如函数调用或增量运算符之类的副作用时,这两种情况才有所不同。例如,以下两个赋值是不相同的:data[i++] *= 2 data[i++] = data[i++] * 2
我认为这意味着我的一行示例应该产生与其他两个相同的结果,因为:
- Flanagan 提到了两个评估发生在
a = a op b
而不是一个,这意味着这实际上与右侧未评估为 an的a op= b
地方不同。a
lval
- 我假设我使用的赋值运算符(例如
a += b
)会算作副作用。
恕我直言,我认为 Flanagan 让这件事变得令人困惑,它似乎与 ECMAScript 约定中的内容相矛盾(由pocka粘贴在下面),但这可能是我的阅读/误解。他说的是不正确还是不清楚?或者,就我一个人吗?