Chained Assignment in JavaScript

· 3 min read · 451 Words · -Views -Comments

I ran into a seemingly easy JavaScript puzzle in a chat group today and still got it wrong, so I’m jotting it down.

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

Wrong Turn #1

I assumed it was equivalent to the code below:

var user = {
  n: 1
};
user = {
  n: 2
};
user.x = user;
console.log(user.x);
/**
 * {n: 2, x: {…}}
 */

Running it in the browser or Node showed the actual answer is undefined.

Wrong Turn #2

I went back to review the assignment operator. For chained assignment specifically:

Chaining the assignment operator is possible in order to assign a single value to multiple variables.

So a = b = c should behave like b = c; a = c;.

By that logic, I rewrote the snippet as:

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

I figured that must be correct, but the browser printed {n: 2}—still wrong. The missing piece? The member-access operator.

The Real Answer

The dot operator for member access has higher precedence than assignment.

Let’s analyze it again:

var user = {
  n: 1
};

user.x = {
  n: 2
};

user = {
  n: 2
};
console.log(user.x);

/**
 * user.x points to the original object (call it “1”).
 * The object literal {n: 2} is assigned to that original object's x.
 * The final assignment rebinds user to a new object (call it “2”).
 * console.log reads x from “2”, which has no such property, so the result is undefined.
 */

A simple question, yet it tripped me up—reminder that fundamentals matter. A few key takeaways:

  1. The dot operator has higher precedence than assignment.

  2. Chained assignment copies a single value into multiple variables, and it evaluates from right to left. You can prove this with a quick Proxy experiment:

    var superman = {
      name: 'clark'
    };
    
    var batman = {};
    var flashman = {};
    
    const batmanProxy = new Proxy(batman, {
      set: function (target, key, value) {
        console.log(`batman: ${key} set from ${target[key]} to ${value}`);
        target[key] = value;
        return true;
      }
    });
    
    const flashmanProxy = new Proxy(flashman, {
      set: function (target, key, value) {
        console.log(`flashman: ${key} set from ${target[key]} to ${value}`);
        target[key] = value;
        return true;
      },
      get: function (target, key) {
        console.log(`flashman: ${key} get from ${target[key]}`);
        return target[key];
      }
    });
    
    batmanProxy.name = flashmanProxy.name = superman.name;
    

    The logs show flashman’s setter firing first. Also note this is not the same as batmanProxy.name = (flashmanProxy.name = superman.name); because the proxy’s getter never runs.

  3. Object assignment copies references, not values.

Final Thoughts

Elementary question, valuable lesson. Back to studying—and back to slinging code.

Authors
Developer, digital product enthusiast, tinkerer, sharer, open source lover