我在Github前端采访问题集中遇到了这个问题:
var foo = {n: 1}; var bar = foo; foo.x = foo = {n: 2};
问题:foo.x的价值是什么?
答案是undefined
。
我做了一些研究,我明白这个问题是(如果我错了,请纠正我):
var foo = {n: 1};
声明一个对象foo
,其属性n
等于1. var bar = foo;
声明了一个对象bar
,该对象引用与foo
相同的对象。foo.x = foo = {n: 2};
等于foo.x = (foo = {n: 2});
foo.x
等于undefined
。但是,bar.x
的值是对象{n:2}
。如果bar
和foo
引用相同的对象,为什么bar.x
在foo.x
为undefined
时获得了价值? foo.x = foo = {n: 2};
中真正发生了什么?
答案 0 :(得分:48)
foo.x = foo = {n: 2};
确定foo.x
引用x
对象的属性{n: 1}
,将{n: 2}
分配给foo
,并指定{{1}的新值} - foo
- {n: 2}
对象的属性x
。
重要的是{n: 1}
引用的foo
是在foo.x
更改之前确定的。
请参阅section 11.13.1 of the ES5 spec:
让 lref 成为评估 LeftHandSideExpression 的结果。
- 醇>
让 rref 成为评估 AssignmentExpression 的结果。
赋值运算符从右到左关联,因此得到:
foo
左手侧在右手侧评估。
答案 1 :(得分:21)
foo.x = foo = {n:2};
这里foo在赋值之前,即在执行语句之前引用 {n:1} 对象。
该陈述可以重写为 foo.x =(foo = {n:2});
在对象术语中,上述陈述可以重写为 {n:1} .x =({n:1} = {n:2});
因为作业只从右到左发生。所以在这里我们只需要检查foo在执行开始之前是指哪个对象。
解决R.H.S: foo = {n:2} ;现在 foo 指的是 {n:2} ;
回到我们留下的问题:
foo.x = foo;
现在L.H.S上的 foo.x仍然是{n:1} .x ,而R.H.S上的 foo是{n:2} 。
因此,在执行此声明之后 {n:1} 将变为 {n:1,x:{n:2}} ,并且仍然指向它。 foo 现在指的是 {n:2} 。
因此在执行时foo.x给出了undefined,因为foo中只有1个值是{n:2}。
但如果您尝试执行bar.x,它将给出{n:2}。 或者如果你只是执行bar,结果将是
对象{n:1,x:对象}
答案 2 :(得分:4)
我以为我会添加另一个,我发现的是,有用的思考方式。
那些最后的变量赋值等同于写bar.x = foo = {n:2};
,因为这些变量只是对内存中同一事物的引用。
换句话说,foo
和bar
最初都引用同一个对象{n:1}
。当您使用foo.x =
时,您正在访问{n:1}
并向其添加x
属性。这可以使用bar
或foo
来完成,因为它们都指向内存中的同一个对象!没有区别。
然后,当您完成该行foo.x = foo = {n:2}
时,您将通过对象文字语法在内存中创建另一个全新对象,并将foo
设置为指向那个对象{n:2}
,而不是现在的{n:1, x: {n: 2}
。但是,这并不会影响foo
向x
添加.one()
属性时指向的内容。
这非常令人困惑,但我认为你认为变量只是指向内存中的位置/对象的指针是有道理的,并且该对象的文字语法不会改变以前存在的对象(即使它们看起来类似)。它创造了一个全新的。
this question的已接受答案的开头也可能有用。
答案 3 :(得分:3)
理解的是,对象变量仅仅是对JavaScript中对象的引用,而不是对象本身。
var foo = {n: 1}
- > foo指真实对象{n:1}
var bar = foo
- > bar现在也是对真实对象的引用{n:1}
棘手的部分当然是第3行:
foo.x = foo = {n: 2}
这相当于:
(reference to {n: 1}).x = (foo = {n: 2})
- >在完全评估这一行之后,foo成为对象{n:2}的引用;但是,由于foo在评估行之前引用原始对象{n: 1}
,因此在评估行之后原始对象{n: 1}
变为{n: 1, x: [reference to]{n: 2}}
,并且可以通过参考bar
。如果没有参考栏,原始对象将被销毁
答案 4 :(得分:3)
据我了解,表情:
foo.x = foo = {n: 2};
与以下内容完全相同:
foo.x = {n: 2} ;
foo = {n: 2};
在此之后,很明显:
bar=={n: 1, x: {n:2}};
foo=={n:2};
foo.x==undefined
答案 5 :(得分:0)
我认为在Javascript中,如果对象不为空,则不能为不存在的属性分配值。因此,在这种情况下,foo对象具有一个{n:1}的属性和值对,因此,由于它不为空且不具有ax属性,因此无法分配,但是由于为bar对象分配的值是foo对象,无论foo是什么,它都将具有值