这与Javascript a=b=c statements。
有关我明白了
foo = foo.x = {n: b}; // console.log(foo) => {n: b}
但是
foo.x = foo = {n: b}; // console.log(foo) => {n: b}
它应该等于:
foo = {n: b};
foo.x = foo; // console.log(foo) => {n: b, x:object}
我在这里错过了什么吗?
答案 0 :(得分:18)
使用:
foo.x = foo = {n: b};
首先部分评估前导foo.x
,足以确定分配的确切目标,然后再继续实际分配。
它表现得更像:
var oldFoo = foo;
foo = {n: b};
oldFoo.x = foo;
This is mentioned in the standard。 {值{1}}的左侧在放置值(1.f)之前进行评估(1.a):
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
1)如果 LeftHandSideExpression 既不是 ObjectLiteral 也不是 ArrayLiteral ,那么
a)让 lref 成为评估 LeftHandSideExpression 的结果。
...
f)表演? PutValue( lref , rval )。
答案 1 :(得分:7)
这是因为你写的时候
var foo = {};
foo.x = foo = {n: b} //a=b=c
在执行该行时,foo指向{}
,但此语句分解为
foo.x = (foo = {n: b}) /a=(b=c)
foo的引用已从{}
更改为{n:b}
但foo
(a)中的foo.x
仍然指向foo
的旧引用,因为在分配开始之前评估左手表达。
根据spec
- 醇>
如果LeftHandSideExpression既不是ObjectLite也不是 ArrayLiteral,
一个。然后让lref成为评估的结果 LeftHandSideExpression。
这意味着在作业foo.x
仍然引用旧foo
之前。
所以,如果你做一点点调整你的例子
var foo = {z:2};
foo.x = foo.n = {n: 1};
在此示例中,您未更改对foo
的引用,仅分配了新属性,因此现在输出
对象{z:2,n:对象,x:对象}
现在,它保留了对旧foo
的引用,因为未分配新引用,因此保留所有属性z
,n
和x
。
答案 2 :(得分:6)
等于
let tmp = foo;
foo = {n: b};
tmp.x = foo;
您可以看到,旧的foo
(在此示例中存储在z
中)已被修改:
> z=foo={};
{}
> foo.x = foo = {n: b};
{ n: 10 }
> foo
{ n: 10 }
> z
{ x: { n: 10 } }
答案 3 :(得分:1)
我明白了。
var foo = {}; // now foo is a reference point to object {}
foo.x = foo = {n:1}; // first foo is refer to a new object {n:1}, then old foo referred object {} set a prop x
// try this to get what you want
var foo = foo1 = {};
foo.x = foo = {n:1};
console.log(foo, foo1) // here foo1 is what you want