What are Primitive and Reference Types in JavaScript?

Understanding how JavaScript treats different data

In a JavaScript interview, they might ask if you understand the difference between primitive and reference data types. Luckily for you, this topic is one of the few in computer science where the names explain it all. There are two ways data types can store info: as a slot in memory, or as a reference to a slot in memory somewhere else. Can you guess which is which?

First up: Primitive types

Primitive data types are: numbers, strings, booleans, undefined, and null (also symbols so check those out). Basically, if it’s storing a simple piece of data, it’s stored simply. When you set a variable with this type, the variable is that exact value and that’s all. If you change that value, the variable simply becomes a new value.

Next: Reference Types

That means the two reference types are objects and arrays (technically one, since arrays are objects). When you create an object, that value is not directly assigned to the variable. Instead, a reference to that value is what gets set. All that variable knows about is the location of the object in memory, not the object itself.

Explaining it with a chore metaphor

Let’s say you need to remind yourself to clean the dishes. If you were to store it primitively, you would take a piece of paper and write down “do the dishes.” But what if your roommate already did them? Now your chore is take out the trash. Since it’s primitively stored, you just take that piece of paper, erase “do the dishes” and write down “take out the trash.”

To save your chores by reference, your roommate would keep a list of all the chores. When you need to know what’s left or cross one off, you ask them, and they access the list. You don’t have the list yourself, you just know where to find it. But enough with metaphors, let’s look at some code.

Code that copies a value is where it counts

This all really comes into play when copying or transfering values. Look at this code that copies primitive values:

let color1 = 'green';

let color2 = color1;

color1 = 'purple'; console.log(color1);

// 'purple'

console.log(color2);

// 'green'

color1 is assigned the string value ‘green’ , which means the variable color1 is essentially the same as just a string 'green' . When we use color1 to assign a value to color2 , it would’ve been the same as if we literally assigned it a string value. So when we reassign color1 ’s value, it has absolutely no impact on color2 . Both values were always just saving strings, they had no lasting bonds between them. This is not the case with reference types. Look:

let car1 = {

wheels: 4,

seats: 2,

};

let car2 = car1;

car1.brand = 'ford'; console.log(car1.brand);

// 'ford'

console.log(car2.brand);

// 'ford'

Huh. We never assigned car2 a brand property, yet it has one. Despite the situations looking the same as our primitive example, the behavior is the opposite. That’s because car1 was never assigned the value of the object, only the reference to it. So if you change car1 , that will alter the same spot in memory that car2 is looking at:

Solving the reference problem

By adding that brand property, we permanently altered the original object. That is called a mutation, and it’s not great when we accidentally do it to more than our intended target. To get around this, we just have to create a new reference to a new object. That way, each variable will point to its own object and not have any overlap. The most common approach is to use Object.assign or the spread operator. For brevity, let’s use a spread:

let car1 = {

wheels: 4,

seats: 2,

};

let car2 = {...car1};

car1.brand = 'ford'; console.log(car1.brand);

// 'ford'

console.log(car2.brand);

// undefined

One last thing

Objects are mutable, meaning they can change (unless you freeze it). However, primitive types are immutable. See, you can’t actually mutate the number 1 into 2 , you just replace the value. Meaning we didn’t change our ‘green’ string, we just straight up replaced it with a new string, ‘purple.’ It’s a sneaky little technicality, but now you know! So good luck on those interviews and as always,

happy coding everyone,

mike

latest article: How to Build a Dynamic, Controlled Form with React Hooks