What Does it Mean that Primitive Values are Immutable in JavaScript?

In JavaScript, you’ll often hear that primitive values are immutable, unlike non-primitive values, which are mutable. It’s important to understand the difference between these value types (also called data types) because it will save you a lot of headaches down the road.

Primitive values are things like:

  • numbers
  • strings
  • booleans

Non-primitive values are:

  • objects
  • functions

Mutable means it can be changed.

Immutable means it cannot be changed.

Non-primitive values are mutable

The following is a list (array) of people assigned to a variable:

let peopleList = ['Arnold', 'Linda', 'Sylvester', 'Dolph']

Now I want to mutate my list. Mutate simply means change. I want to swap out Arnold with Jean-Claude, and print out the result:

let peopleList = ['Arnold', 'Linda', 'Sylvester', 'Dolph']

peopleList[0] = 'Jean-Claude'

console.log(peopleList)

It worked! We just made a mutation on an existing value. In this case, the existing value was an array (list), or more specifically, an array object.

In JavaScript, non-primitive values are mutable (changeable).

Primitive values are immutable

The following is a text (string) value that gets assigned to a variable:

let person = 'Ernold'

Crap, unfortunately, we misspelled Arnold by using an E instead of an A in the first letter of his name. Let’s change that quickly and print out the result:

let person = 'Ernold'

person[0] = 'A' 

console.log(person) // output: Ernold

Wait, what? Why does it print out “Ernold”? Didn’t we just swap out E with A!?

No, because the value we’re trying to mutate is a string, which is a primitive value — and all primitive values are immutable (unchangeable).

Only non-primitive values (objects & functions) are mutable.

Confused?

It’s totally normal to be confused about this stuff at the beginning of your JavaScript learning journey because on the surface the examples above look and even behave similarly — in some situations.

Let’s print out the first name from our array from earlier:

let peopleList = ['Arnold', 'Linda', 'Sylvester', 'Dolph']

console.log(peopleList[0]) // output: "Arnold"

No surprises there, it prints out "Arnold".

Now let’s print out the first letter our string from earlier (the misspelled name):

let person = 'Ernold'

console.log(person[0]) // output: ??

What do you think will happen?

...

...

It worked! It prints out "E"!

Did you expect the above to not work?

Either way, the important lesson here is that you can access a primitive value in a similar way to how you access non-primitive values, but you can’t change (mutate) it. That’s the big difference (access vs. mutate).

In JavaScript, primitive values are read-only, whereas non-primitive values (objects/arrays, functions) are both read & write.

That’s why we could change (mutate) the first item value of our array from Arnold to Jean-Claude earlier, but we can’t fix a simple spelling error from "Ernold" to "Arnold" — because it’s a string, and strings/primitive values are immutable.

Variables vs. Values

(I know what some of you are thinking)

Even though we just concluded that primitive values are immutable, I’m still determined to fix the spelling mistake of “Ernold”. Let’s try something new!

Take a look at the following code (read it, carefully):

let person = 'Ernold'

person = 'Arnold'

console.log(person) // output: ??

Considering what you’ve learned about primitive values, such as strings, do you think the above will print out Arnold, yes or no?

...

(Think about it)

...

It does print out Arnold!

Some of you already know why, but if you didn’t, that’s normal, you will experience an “aha moment” in a moment. Read the following paragraph carefully.

The code above works because we’re not mutating the string value, we’re not even touching it. Instead, we’re assigning a new string value called 'Arnold' to the person variable so it no longer references (points to) the 'Ernold' string value.

Primitive values can’t change, but variables can!

Variables are not values, so the rules of mutability or immutability are not the same. Variables just point to values.

We never touched the former string value 'Ernold' directly, we just told our person variable to point to another string called 'Arnold' and then used console.log() to print out the result.

Some of you might think I’m beating the dead horse here, but it’s important that you have this realization about how JavaScript works. Repetition is your friend.

Note: the type of variables we’ve used throughout this entire tutorial is of the keyword type let — which is mutable, as you just saw in the previous code example. Had we been using a const variable, the situation would have been different — but I’ll save that topic for a different tutorial.

In summary:

In JavaScript:

  • non-primitive values can be referred to, accessed — and mutated.
  • primitive values can be referred to, accessed — but not mutated.
  • variables and values are two different things, different rules apply.