Cassidy Williams

Software Engineer in Chicago

Cassidy's face

Why JavaScript variables don't always update


I was helping a friend of mine with some technical interview questions, and a lot of them were very much like “what does this code output”-style questions (which I deeply dislike, I think these questions are more indicative of someone knowing really specific aspects of a language and less about software engineering, but I digress). One of them though I thought was interesting enough to write a technical explanation.

Values and objects

Look at this JavaScript code:

let [CLOSED, OPEN] = [{}, {}]

CLOSED = {
  cake: OPEN
}

OPEN = {
  fish: 5
}

console.log(CLOSED); // cake is {}

Why is it that CLOSED is not { cake: { fish: 5 }}?

It’s because of how JavaScript assigns values and objects. In JavaScript, when you assign an object to another variable, you’re not creating a copy of that object. You’re creating a reference to that object.

So what’s happening here is that CLOSED and OPEN are both initialized as empty objects {}. When we assign CLOSED to { cake: OPEN }, it’s pointing at that empty OPEN object.

When you change OPEN to { fish: 5 } in this way, it assigns OPEN to a new object, and leaves the previously empty object behind. I say it like that because CLOSED still refers to the old empty object, and not the new one!

I say “in this way” because there’s another way to change OPEN: modify the existing empty object in place, so that CLOSED.cake references it even as it changes.

let [CLOSED, OPEN] = [{}, {}]

CLOSED = {
  cake: OPEN
}

OPEN.fish = 5;

console.log(CLOSED); // This now logs { cake: { fish: 5 }}

Do you see how this is different? Instead of creating an entirely new object for OPEN to be reassigned to, we modify the properties of OPEN instead. CLOSED is still pointing to that object, and it’s just not a “left behind” object anymore!

I hope you don’t have to have this as an interview question, but you may run into similar problems as you build systems that use this as a concept.

User management example

Let’s say you have some kind of user management system. You might have an initial state of user accounts:

let state = {
  users: [
    { id: 1, name: "Cassidy", role: "admin" },
    { id: 2, name: "Yesenia", role: "user" },
    { id: 3, name: "Alan", role: "user" },
    { id: 4, name: "Gabor", role: "user" },
  ]
};

If you wanted to promote a user to be an admin, you’d want to change the user object (by reference):

function promoteToAdmin(user) {
  user.role = "admin";
}

(to reiterate: this changes the existing user object)

If you wanted to remove a user, you would want to change the state object (by value):

function removeUserById(userId) {
  state.users = state.users.filter(user => user.id !== userId);
}

(this creates a new array with the filtered result)

So, if you want to promote Yesenia to admin:

let yesenia = state.users[1]; // Reference to Yesenia's object
promoteToAdmin(yesenia); // Directly changes her object

console.log(state.users);

Try this in your console! You’ll see that the users array is all the same, except that Yesenia is an admin now.

If we wanted to remove Alan next:

removeUserById(3);

console.log(state.users);

Again, this does not change the original users array, but returns a new array and assigns users to it.

If you run this yourself, note in your console that Yesenia is still an admin, showing that the update persisted!

Wow, I love JavaScript

Good for you. I have a love/hate relationship with it. But I mostly love it too, I guess. Kind of. I should value it more. Eh?? Ehhh????

Okay anyway, I hope this is helpful!


View posts by tag

#advice #personal #musings #events #technical #learning #work #meta