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

Lis*_*isa 9 javascript

我是JavaScript的新手,刚刚遇到了这个问题.无法通过谷歌搜索和搜索stackoverflow来解决它.代码段如下:

var a = { n : 1};    
var b = a;    
a.x = a = {n:  2};    
console.log(a.x);
console.log(b.x);
Run Code Online (Sandbox Code Playgroud)

根据我目前的知识,a.x = a = {n:2};等于:

这最终使得等于{n:2, x:{n:2}}.所以a.x应该等于{n:2},因为b = a,所以b.x = {n:2}.但是我在浏览器中运行的结果是:alert(a.x)undefinedalert(b.x)[object object].

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

JLR*_*she 7

这是运算符优先级的问题,而这个问题是有3个运营商这里涉及到:=,=,和..

.具有更高的运算符优先级=,这意味着在分配发生之前a.x进行评估.之后,重新分配mid语句不会影响表达式中的值,因为它已经被评估过了.aaa.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);
Run Code Online (Sandbox Code Playgroud)

我们在这里看到的是,在我们正在讨论的语句的过程中,它的setter a被访问之前被访问,并且它只被访问一次.这告诉我们之前a.x正在评估. a.x = ....

你出错的地方是那个陈述实际上是这样估算的:

a = {n:  2}
[the value that a referred to before the statement started executing].x = {n : 2};
Run Code Online (Sandbox Code Playgroud)

换句话说,标识符a在语句开始执行之前被"绑定",属性引用将在语句的持续时间内引用该绑定值.

在这种情况下,[the value that a referred to before the statement started executing]相当于b,但它不等于新值a.这就是为什么b.x有价值而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);
Run Code Online (Sandbox Code Playgroud)

这会产生与原始代码相同的结果.

ECMAScript的规格规定了该过程用于评估AssignmentExpression形式的LeftHandSideExpression = AssignmentExpression.前两个步骤是:

  1. 让lref成为评估LeftHandSideExpression的结果.
  2. 让rref成为评估AssignmentExpression的结果.

这清楚地表明,在评估右侧之前评估分配的左侧.

  • 这与优先级(或关联性)无关.相反,它是评估操作数的顺序,特别是操作数"ax"和"a = {n:2}".结果令人惊讶的原因(对我而言)是`=`是右关联的,但仍然从左到右评估操作数.除了那个挑剔,你的答案是正确的,非常有用. (2认同)

Nag*_*i A 0

在这种情况下 ax 是未定义的,因为

由于第二次赋值 (a = {n:2}),ax 中的引用已更改为新的引用值

使用旧引用读取属性值是未定义的,因为它已更改

要查看差异,请添加新属性,如下所示

ax = ay = {n:2} // 这不会改变a的引用

console.log(a.x);//{n:2}
console.log(a.y);//{n:2}
console.log(b.x);//{n:2}
Run Code Online (Sandbox Code Playgroud)

https://codepen.io/nagasai/pen/JpeENv

来自类似问题的更多详细信息 - How does ax = a = {n: b} work in JavaScript?