JavaScript 代码技巧:foo.x 的值是多少
JavaScript code trick: What's the value of foo.x
我在一个GitHub前端面试题集里发现了这个问题:
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
Question: What is the value of 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};
到底发生了什么?
foo.x = foo = {n: 2};
判断foo.x
引用了{n: 1}
对象的属性x
,将{n: 2}
赋值给foo
,并赋值给foo
foo
的新值 – {n: 2}
– 到 {n: 1}
对象的 属性 x
。
重要的是foo.x
所指的foo
是在foo
变化之前就确定的
见section 11.13.1 of the ES5 spec:
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
赋值运算符从右到左关联,所以你得到:
foo.x = (foo = {n: 2})
左侧先于右侧求值。
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} }
并且 bar 仍然引用它。
foo
现在指的是 {n:2}
。
所以在执行时 foo.x
给出 undefined
因为 foo
中只有 1 个值 {n:2}
.
但是如果你尝试执行 bar.x
,它会给出 {n:2}
。
或者,如果您只执行 bar
,结果将是
Object {n: 1, x: Object}
我想我会添加另一个我发现的有用的思考方式。
那些最后的变量赋值相当于写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
属性 时指向的内容。
这很令人困惑,但我认为您考虑以下事实是有道理的:变量只是内存中指向 places/objects 的指针,并且对象字面量语法不会更改先前存在的对象(即使他们看起来很相似)。它正在创建一个全新的。
this question 已接受答案的开头也可能有帮助。
需要理解的是,对象变量只是对 JavaScript 中对象的引用,而不是对象本身。
var foo = {n: 1}
-> foo指的是真实对象{n:1}
var bar = foo
-> bar 现在也是对真实对象 {n: 1}
的引用
棘手的部分当然是第三行:
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
。如果没有reference bar,原对象会被销毁
据我理解表达:
foo.x = foo = {n: 2};
完全一样:
foo.x = {n: 2} ;
foo = {n: 2};
在此之后很明显:
bar=={n: 1, x: {n:2}};
foo=={n:2};
foo.x==undefined
我认为在 Javascript 中,您不能为 属性 赋值,如果对象不为空,则该值不存在。所以在这种情况下 foo 对象有一个 属性 和值对,它是 {n:1} 所以因为它不是空的并且它没有 x 属性 ,你不能分配但是因为你分配bar object a value which is foo object , it will have the value whatever the foo is
我在一个GitHub前端面试题集里发现了这个问题:
var foo = {n: 1}; var bar = foo; foo.x = foo = {n: 2};
Question: What is the value of 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};
到底发生了什么?
foo.x = foo = {n: 2};
判断foo.x
引用了{n: 1}
对象的属性x
,将{n: 2}
赋值给foo
,并赋值给foo
foo
的新值 – {n: 2}
– 到 {n: 1}
对象的 属性 x
。
重要的是foo.x
所指的foo
是在foo
变化之前就确定的
见section 11.13.1 of the ES5 spec:
Let lref be the result of evaluating LeftHandSideExpression.
Let rref be the result of evaluating AssignmentExpression.
赋值运算符从右到左关联,所以你得到:
foo.x = (foo = {n: 2})
左侧先于右侧求值。
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} }
并且 bar 仍然引用它。
foo
现在指的是 {n:2}
。
所以在执行时 foo.x
给出 undefined
因为 foo
中只有 1 个值 {n:2}
.
但是如果你尝试执行 bar.x
,它会给出 {n:2}
。
或者,如果您只执行 bar
,结果将是
Object {n: 1, x: Object}
我想我会添加另一个我发现的有用的思考方式。
那些最后的变量赋值相当于写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
属性 时指向的内容。
这很令人困惑,但我认为您考虑以下事实是有道理的:变量只是内存中指向 places/objects 的指针,并且对象字面量语法不会更改先前存在的对象(即使他们看起来很相似)。它正在创建一个全新的。
this question 已接受答案的开头也可能有帮助。
需要理解的是,对象变量只是对 JavaScript 中对象的引用,而不是对象本身。
var foo = {n: 1}
-> foo指的是真实对象{n:1}
var bar = foo
-> bar 现在也是对真实对象 {n: 1}
棘手的部分当然是第三行:
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
。如果没有reference bar,原对象会被销毁
据我理解表达:
foo.x = foo = {n: 2};
完全一样:
foo.x = {n: 2} ;
foo = {n: 2};
在此之后很明显:
bar=={n: 1, x: {n:2}};
foo=={n:2};
foo.x==undefined
我认为在 Javascript 中,您不能为 属性 赋值,如果对象不为空,则该值不存在。所以在这种情况下 foo 对象有一个 属性 和值对,它是 {n:1} 所以因为它不是空的并且它没有 x 属性 ,你不能分配但是因为你分配bar object a value which is foo object , it will have the value whatever the foo is