这段JavaScript代码片段的结果是什么?为什么?

时间:2018-02-27 03:20:04

标签: javascript

我是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)undefinedalert(b.x)[object object]

有人可以解释原因吗?非常感谢。

4 个答案:

答案 0 :(得分:7)

这是运算符优先级的问题,问题是这里涉及三个运算符:==.。< / p>

.的运算符优先级高于=,这意味着{<1}}在分配之前进行评估。之后,重新分配a.x mid语句不会影响表达式aa的值,因为它已经过评估。

我们可以使用以下代码观察:

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. 让lref成为评估LeftHandSideExpression的结果。
  2. 让rref成为评估AssignmentExpression的结果。
  3. 这清楚地表明,在评估右侧之前,评估左侧

答案 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中的例程混淆了(应该这样)。

基本上问题是评估的顺序。

这只是我在尝试之后对它的看法。我想听听社区的其他答案。