【发布时间】:2013-11-03 14:57:38
【问题描述】:
我想快速连续地使用运算符对几个变量做一些事情。我不认为我想做什么本身很重要;我的问题更多是关于 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(第 6 版)(特别是在 4.11.1“操作分配”下)中寻找了为什么这可能会出现,但在那里一无所获。 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中发生的两个评估,而不是一个,这意味着这实际上与a op= b不同,其中a没有被评估为右侧的lval。 - 我假设我使用的赋值运算符(例如
a += b)会被视为副作用。
恕我直言,我认为 Flanagan 让这变得令人困惑,它似乎与 ECMAScript 约定中的内容相矛盾(由pocka 粘贴在下面),但这可能是我的阅读/误解。他说的是不正确还是不清楚?还是只有我一个人?
【问题讨论】:
-
用手写数学写出来,用铅笔会得到相同的结果....真的认为你回答了自己的问题
-
@charlietfl 示例 1 和 2 是示例 3 的简易版本。如果第一次评估是
a + b而不是a += b,我可以理解结果a === 22。我的问题是关于行为,因为这是对a的分配,在我们进行最终分配/评估时似乎已经忘记了。 -
括号的从右到左的优先级使您可以将
a添加到括号中评估的内容中,而前面的两个示例将b 添加到a...然后在右侧添加相同的amont。没有什么时髦的。我认为这是你认为逻辑有缺陷并想深入研究原因的那些心灵融化的事情之一......当它是你自己的思想在欺骗你时。我们都去过那里 -
@charlietfl 我喜欢“你自己的想法在欺骗你”的部分。
-
@charlietfl 你对我自己的想法可能是正确的。我已经更新了这个问题(希望)解释我的困惑。感谢您说“我们都去过那里”——这实际上令人欣慰:-)
标签: javascript operators variable-assignment