Variables will not, Constants are not


Bear with me, I tend to dive deep and work my way back out. In this case, there are some things to understand about javascript, and the way variables work.

Often, books or classes will use the example of "A variable is like a box. You put a value in, and then you can change the contents of that box by simply replacing the value." And that sounds neat, and approachable, and understandable... and is completely wrong.

Dan Abramov recently had an email series, Just Javascript, and the greatest understanding for me was this concept: A variable is not a box. It doesn't contain the value. Instead, the value is stuck into the browser's allocated memory, and the variable is wired to that.

Think of something like an antique switchboard, with a grid of sockets that wires can be plugged and unplugged, moved from one location to another, connecting and reconnecting. That's the visual I use for variables.

So here's the thing: when we declare and initialize a variable, there are a few things that happen:

  1. We tell javascript to internally place this variable name in a register.
  2. We point that variable to a location in the browser's memory.
  3. We assign the value we're connecting into that variable in that memory location.

So we tell javascript "Hey, I'm declaring a variable, so create that in your internal registers. Then, wire it to the memory location where you store this particular value." Two end points... and a wire.

Yeah, but why does this matter?

As it happens, this is significant. But it only becomes significant when you grok this concept: Data Is Immutable. A value, once assigned to a variable, doesn't change. Doesn't matter if its a const, a let or a var, the data in that memory location we're pointing to is fixed.

Did I hear heads explode?

I mean that. A value, once pushed into a memory location, doesn't change. What does change, if we look back at our "switchboard" metaphor, is the memory position to which we point.

Say we have something like this:

let age =  38;
// and later...

What we've done is declare and initialize a variable, age, and then we've updated its value. But internally, javascript has pulled that value from that memory location, incremented it in the CPU, assigned the updated value to a new memory location, and moved the "wire" from our variable to this new location. The original data, 38, has remained unchanged. If another variable were pointing to that same memory location, it would still see the original value, not the incremented one.

If, on the other hand, we had done

const meaningOfLife = 42;
// and later...
meaningOfLife = 'The meaning of life is: '+meaningOfLife;

... well, we'd get an error. Why? Because, when we initialized meaningOfLife, we set it to a const. We explicitly tell javascript, "Hey, no matter what, do not re-wire this variable!" That variable points at that memory location... and data is immutable.

But but but...!

An argument against the whole const thing that often comes up is the case of arrays or objects. You can manipulate and change them, right? Even if they're in a const!

And there's a reason for that. The const declaration sets the variable to the position in memory where that thing starts. If we had the following:

const arr = [];
// we could do the following with no error:
// but we couldn't do this:
arr = [1, 3, Math.PI];

The const arr declaration is setting the variable to the location in memory where our array begins - but there's no easy way of telling that memory location that it should be hard-wired to point to the NEXT one. In other words, the variable itself will always point to the original location, but internally, that array is simply a series of memory references.

The same with objects: when we do const myObj={...}, we have assigned a memory location to our object, and we have wired myObj to only point to that memory location. But what happens at that memory location isn't fixed, without some changes.

This seems silly.

You're absolutely right. And this is largely theoretical "I can't sleep tonight" ruminations. But there is a point.

When you find yourself in a conversation with a fellow developer, and they say "primitives in javascript are passed by value, but arrays and objects are passed by reference", you can see that that is wrong. Both are passed by reference.

When we do something like console.log(foo), what we are telling console.log is "Hey, go to the memory location foo points to, and use the value you find there." Doesn't matter if its a Boolean, String, Array or Map, it points to a memory location, and we are passing that location.

If our function were to change that value, that's where things get dicey. If the value we've changed is a primitive, then our original variable, which points to the memory location that was passed in, continues to point to that location. If our function has changed the value, it has consumed a different memory location.

On the other hand, if we were working with an array (for example), and we arr.push(...) into that array, we are still pointing at the same memory location. We have updated some of the array's internal pointers, but our function and the original variable point at the same memory location.

And the upshot is...?

By value or by reference is a trick question, in the javascript world. It's a moot point. When an interviewer asks you that one, smile knowingly. You got this.

Developer | Tech Enthusiast | Coding Mentor