The “const” Deception

Exploring the difference between assignment and mutation in JavaScript

Introduction

The const keyword in JavaScript is used to declare a constant. Constants are often thought of as “variables that can't change”:

js

Curiously, though, when I create an object using const, I'm free to change it:

js

How come I was able to change the person variable? I used const!

To make sense of this apparent contradiction, we need to learn about the difference between assignment and mutation. This is a core concept in JavaScript, and so many things make more sense when you have a clear understanding of this distinction.

Let's go!

Link to this heading
Variable names as labels

So, here's a perfectly-valid JavaScript program:

js

Here's another one:

js

In both of these examples, I'm creating some stuff. A number, and an array. When the code runs, this data will be created and stored in the computer's memory.

These programs aren't terribly useful, however. I'm creating some data, but I have no way of accessing it!

Variables allow us to stick a label on the stuff we create, so that we can reference it later:

js

When I was first learning to program, I thought that the code was executed from left to right: first we create a fruits variable, like an empty box, and then we assemble our array within that box.

It turns out that this isn't really the right mental model. It's more accurate to say that the array gets created first, and then we point our fruits label at it.

Link to this heading
Reassigning our labels

When we use the let keyword to create a variable, we're able to change which “thing” that label refers to.

For example, we can point our fruits label at a new value:

We're not modifying the data, we're modifying the label. We're detaching it from that original array, and connecting it to a new one.

By contrast, variables created with const cannot be reassigned:

This is the fundamental difference between let and const. When we use const, we create an indestructible link between a variable name and a piece of data.

Here's the thing, though: we're still allowed to modify the data itself! As long as the label remains intact.

For example, with an array, we can add/remove items from that array without issue. The fruits variable is still connected to the same array:

This is known as mutation. We're editing the value of the array by adding / removing items.

Here's another example, using an object instead of an array. We can edit the keys/values within the object, as long as the label keeps pointing to the same object:

There's a fundamental distinction between re-assignment (pointing a variable name at a new thing) and mutation (editing the data within the thing).

When we create a constant with const, we can be 100% sure that the variable will never be re-assigned, but no promises are made when it comes to mutation. const doesn't block mutation at all.

There's one more wrinkle here, too: “primitive” data types like strings and numbers are immutable. This makes things even more confusing. We'll discuss in the next section.

Link to this heading
Primitive data types

So far, all of the examples we've seen have involved objects and arrays. But what about if we have a “primitive” data type, like a string, a number, or a boolean value?

Let's use a number as an example:

js

How should we interpret this? Are we reassigning the age label to a new value, or are we mutating this number, editing 36 to be 37?

Here's the deal: all primitive data types in JavaScript are immutable. It's impossible to "edit" the value of a number. We can only reassign the variable to a different value.

Here's how I like to think about it: Pretend that there's a big list of all possible numbers. We've assigned our age variable to the number 36, but we can point it at any other number in our list:

To be clear, the browser doesn't literally have a big index of all possible numbers. The point I'm hoping to illustrate here is that the numbers themselves can't be changed. We can only change which number the label is pointing to.

This is true for all primitive value types, including strings, boolean values, null, and so on.

Link to this heading
Additional resources

JavaScript is a deceptively tricky language, and it takes a long time to get really comfortable with it!

Here are some additional resources you might find useful:

Last Updated

June 27th, 2023

Hits

A front-end web development newsletter that sparks joy

My goal with this blog is to create helpful content for front-end web devs, and my newsletter is no different! I'll let you know when I publish new content, and I'll even share exclusive newsletter-only content now and then.

No spam, unsubscribe at any time.



If you're a human, please ignore this field.