我知道赋值运算符是右关联的.
所以例如 x = y = z = 2
相当于(x = (y = (z = 2)))
既然如此,我尝试了以下方法:
foo.x = foo = {a:1}
我期望foo
使用value创建对象{a:1}
,然后x
将创建属性,该属性foo
将只是foo
对象的引用.
(实际上,如果我要将多个赋值语句分成两个单独的语句,会发生什么foo = {a:1};foo.x = foo;
)
结果实际上是:
ReferenceError:未定义foo(...)
那么我尝试了以下内容:
var foo = {}; foo.x = foo = {a:1};
现在我不再得到例外但是foo.x
未定义!
为什么作业不按我的预期工作?
var
关键字创建的变量相关联.这不是问题所在.关联性和评估顺序之间存在重要差异.
在JavaScript中,即使赋值操作符组从右到左的操作数进行评价左至右分别是执行实际任务之前(这也发生从右到左).考虑这个例子:
var a = {}; var b = {}; var c = a; c.x = (function() { c = b; return 1; })();
变量c
最初引用a
,但赋值的右侧设置c
为b
.分配了哪个属性,a.x
或者b.x
?答案是a.x
因为在c
仍然引用的情况下,首先评估左侧a
.
通常,表达式x = y
的计算方法如下:
评估x
并记住结果.
评估y
并记住结果.
将步骤2的结果分配给步骤1的结果(并将前者作为表达式的结果返回x = y
).
多项任务会发生什么情况,如x = (y = z)
?递归!
评估x
并记住结果.
评估y = z
并记住结果.去做这个:
评估y
并记住结果.
评估z
并记住结果.
将步骤2.2的结果分配给步骤2.1的结果(并将前者作为表达式的结果返回y = z
).
将步骤2的结果分配给步骤1的结果(并将前者作为表达式的结果返回x = (y = z)
).
现在让我们看看你的例子,稍加编辑:
var foo = {}; var bar = foo; // save a reference to foo foo.x = (foo = {a:1}); // add parentheses for clarity
foo.x
在foo
被分配之前进行评估{a:1}
,因此该x
属性被添加到原始{}
对象(您可以通过检查来验证bar
).