最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

What's the result of this JavaScript code snippet, and why? - Stack Overflow

programmeradmin5浏览0评论

I'm a newby of JavaScript and just met this question. Can't figure it out by googling and searching on stackoverflow. Code snippet is as following:

var a = { n : 1};    
var b = a;    
a.x = a = {n:  2};    
console.log(a.x);
console.log(b.x);

I'm a newby of JavaScript and just met this question. Can't figure it out by googling and searching on stackoverflow. Code snippet is as following:

var a = { n : 1};    
var b = a;    
a.x = a = {n:  2};    
console.log(a.x);
console.log(b.x);

According to my current knowledge, a.x = a = {n:2}; equals to :

a = {n : 2};
a.x = a;

Which eventually make a equals to {n:2, x:{n:2}}. So a.x should equal to {n:2}, and because b = a, so b.x = {n:2}. But the result I run in browser is : alert(a.x) is undefined and alert(b.x) is [object object].

Can someone explain why? thanks a lot.

Share Improve this question edited Feb 27, 2018 at 3:21 Sterling Archer 22.4k19 gold badges85 silver badges121 bronze badges asked Feb 27, 2018 at 3:20 LisaLisa 1603 silver badges11 bronze badges 0
Add a ment  | 

4 Answers 4

Reset to default 7

This is a matter of operator precedence, and the matter is that there are three operators involved here: =, =, and ..

. has higher operator precedence than =, which means that a.x is evaluated before the assignments take place. After that, reassigning a mid-statement cannot affect the value of a in the expression a.x because it has already been evaluated.

We can observe this with the following code:

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);

What we can see here is that a's getter is being accessed before its setter in the process of the statement we're talking about, and it's only being accessed once. This tells us that a.x is being evaluated before a.x = .....

Where you're going wrong is that that statement actually evaluates like this:

a = {n:  2}
[the value that a referred to before the statement started executing].x = {n : 2};

In other words, the identifier a is "bound" before the statement begins executing and property references will refer to that bound value for the duration of the statement.

In this case, [the value that a referred to before the statement started executing] is equivalent to b, but it's not equivalent to the new value of a. That's why b.x has a value and a.x does not.

You could say that the process works out to be something like this:

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);

and this produces the same oute as your original code.

The ECMAScript Spec lays out the procedure for evaluating an AssignmentExpression of the form LeftHandSideExpression = AssignmentExpression. The first two steps are:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let rref be the result of evaluating AssignmentExpression.

This clearly shows that the left hand side of an assignment is evaluated before the right hand side is evaluated.

The code

a.x = a = {n:2};

is the same as

var a = b = 1;

both variables a and b will be set to 1;

Now since you are working with an object and assigning a value to itself ( you would actually be creating a loop, but non the less the routine in JS gets confused ( which it should ).

basically the issue is the order of evaluation.

This is just my take on it after experimenting with it. I Would like to hear what other answers the munity has though.

You've run into something called operator precedence/associativity.

Consider their example:

a = b = 5;

with the expected result that a and b get the value 5. This is because the assignment operator returns the value that is assigned. First, b is set to 5. Then the a is also set to 5, the return value of b = 5, aka right operand of the assignment.

This breaks down to:

b = 5
a = the return of b which is now 5.

a.x = a = {n:  2};

Breaks down into:

a = {n: 2}
a.x = the return of a = {n: 2}

Since b is a reference to a, it is altered after the assignment.

a.x in this scenario is undefined because

a reference in a.x has been changed to new reference value due to second assignment ( a = {n:2})

Reading value of property with old reference is undefined , as it got changed

To see difference add new property , something like this

a.x = a.y = {n:2} // this will not change the reference of 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

More details from the similar question here - How does a.x = a = {n: b} work in JavaScript?

发布评论

评论列表(0)

  1. 暂无评论