我是JavaScript的新手,刚刚遇到了这个问题。无法通过谷歌搜索和搜索stackoverflow来解决它。代码段如下:
var a = { n : 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b.x);
根据我目前的知识,a.x = a = {n:2};
等于:
a = {n : 2};
a.x = a;
最终将等于{n:2, x:{n:2}}
。因此a.x
应该等于{n:2}
,因为b = a
,所以b.x = {n:2}
。
但我在浏览器中运行的结果是:alert(a.x)
为undefined
,alert(b.x)
为[object object]
。
有人可以解释原因吗?非常感谢。
答案 0 :(得分:7)
这是运算符优先级的问题,问题是这里涉及三个运算符:=
,=
和.
。< / p>
.
的运算符优先级高于=
,这意味着{<1}}在分配之前进行评估。之后,重新分配a.x
mid语句不会影响表达式a
中a
的值,因为它已经过评估。
我们可以使用以下代码观察:
a.x
我们在这里看到的是var _a;
var logging = false;
Object.defineProperty(window, 'a', {
get: function () {
if (logging) {
console.log('getting a');
}
return _a;
},
set: function (val) {
if (logging) {
console.log('setting a');
}
_a = val;
}
});
a = { n : 1};
var b = a;
logging = true;
a.x = a = {n: 2};
logging = false;
console.log(a.x);
console.log(b.x);
的getter是在我们正在谈论的语句的过程中之前访问,并且它只被访问一次。这告诉我们{<1}}在 a
之前正在评估。
你出错的地方是那个陈述的实际评估是这样的:
a.x
换句话说,标识符a.x = ....
在语句开始执行之前是“绑定”的,属性引用将在语句的持续时间内引用该绑定值。
在这种情况下,a = {n: 2}
[the value that a referred to before the statement started executing].x = {n : 2};
相当于a
,但它不等同于[the value that a referred to before the statement started executing]
的新值。这就是b
有一个值而a
没有的原因。
你可以说这个过程是这样的:
b.x
,这会产生与原始代码相同的结果。
ECMAScript Spec列出了评估表单 LeftHandSideExpression = AssignmentExpression AssignmentExpression 的过程>。前两步是:
这清楚地表明,在评估右侧之前,评估左侧。
答案 1 :(得分:0)
a.x未定义,因为
由于第二次分配(a = {n:2}),a.x中的引用已更改为新的参考值
使用旧引用读取属性的值是未定义的,因为它已更改
要查看区别,请添加新属性,例如
a.x = a.y = {n:2} //这不会改变 a
的引用console.log(a.x);//{n:2}
console.log(a.y);//{n:2}
console.log(b.x);//{n:2}
https://codepen.io/nagasai/pen/JpeENv
此处类似问题的详细信息 - How does a.x = a = {n: b} work in JavaScript?
答案 2 :(得分:0)
你遇到了一个名为operator precedence/associativity
的东西。
考虑他们的例子:
a = b = 5;
预期结果a和b得到值5.这是因为 赋值运算符返回已分配的值。首先,b 设置为5.然后a也设置为5,返回值b = 5, 又名作业的右操作数。
这分解为:
b = 5
a = the return of b which is now 5.
a.x = a = {n: 2};
分解为:
a = {n: 2}
a.x = the return of a = {n: 2}
由于b是对a的引用,因此在赋值后会更改。
答案 3 :(得分:0)
代码
a.x
与
相同var a = { n : 1};
var b = a;
var temp = a;
var newVal = {n: 2};
a = newVal;
temp.x = newVal;
console.log(a.x);
console.log(b.x);
变量a和b都将设置为1;
现在,因为你正在使用一个对象并为自己赋值(你实际上是在创建一个循环,但不是JS中的例程混淆了(应该这样)。
基本上问题是评估的顺序。
这只是我在尝试之后对它的看法。我想听听社区的其他答案。