Whenever you create a variable in JavaScript, that variable can store one of two types of data, a primitive value or a reference value. If the value is a number
, string
, boolean
, undefined
, null
, or symbol
, it's a primitive value. If it's anything else (i.e. typeof object
), it's a reference value.
Primitive ValuesnumberstringbooleanundefinednullsymbolReference Valuesanything that is "typeof" "object"objectsarraysfunctions
const age = 28; // primitiveconst name = "Tyler"; // primitiveconst loading = false; // primitiveconst user = undefined; // primitiveconst response = null; // primitiveconst counter = Symbol("counter"); // primitiveconst user = { name: "Tyler" }; // referenceconst friends = ["Jake", "Mikenzi"]; // referenceconst doThing = () => ({}); // reference
On the surface primitive values and reference values look the same, but under the hood they behave much differently. The key difference can be seen in how they store their value in memory. If you looked at the in-memory value of a primitive, you'd see the actual value itself (28
, 'Tyler'
, false
, etc). If you looked at the in-memory value of a reference type, you'd see a memory address (or a "reference" to a spot in memory). In practice though, what difference does it make? Let's take a look at some examples.
let surname = "McGinnis";let displayName = surname;surname = "Anderson";console.log(surname); // 'Anderson'console.log(displayName); // 'McGinnis'
First we create a variable called surname
and assign the string McGinnis
to it. Then we create a new variable called displayName
and assign it to whatever the in-memory value of surname
is, which happens to be McGinnis
. From there we change the in-memory value of surname
to be Anderson
. Now, when we log surname
we get Anderson
and when we log displayName
we get McGinnis
. Though this example demonstrates that the in-memory value of a primitive is the value itself, there's nothing surprising or really interesting going on here.
Let's look at a similar example but instead of using a primitive value, let's use a reference value.
let leo = {type: "Dog",name: "Leo",};let snoop = leo;snoop.name = "Snoop";console.log(leo.name); // Snoopconsole.log(snoop.name); // Snoop
First we create a variable called leo
and assign it to an object which has two properties, type
and name
. Then we create a new variable called snoop
and assign it to whatever the in-memory value of leo
is, which is the reference to the spot in memory where the leo
object is located. At this point, both leo
and snoop
are referencing the same spot in memory. What that means is when we modify snoop.name
, because snoop
and leo
are referencing the same spot in memory, it's as if we also modified leo.name
. That's why when we log leo.name
and snoop.name
we get the same value, Snoop
.
Let's look at one more example to cement your understanding. What do you think happens when, using the identity operator (===
), we compare two primitives that have the same value?
const name = "Tyler";const friend = "Tyler";name === friend; // true
Here we see that because name
and friend
have the same value, Tyler
, when comparing them, we get true
. This probably seems obvious but it's important to realize that the reason we get true
is because, with the identity operator, primitives are compared by their value. Since both values equal Tyler
, comparing them evaluates to true
.
Now, what about reference values?
const leo = {type: "Dog",name: "Leo",};const leito = {type: "Dog",name: "Leo",};leo === leito; // false
Even though leo
and leito
have the same properties and values, when comparing them with the identity operator, we get false
. The reason for that is because, unlike primitive values, reference values are compared by their reference, or their location in memory. Above, even though leo
and leito
have the same properties and values, they're occupying different locations in memory.
Both these examples demonstrate how primitive types are compared by their value while reference types are compared by their reference.
An interesting by-product of primitive values is that they're always immutable. This make sense if you think of primitives in terms of their in-memory value. We said earlier that "if you looked at the in-memory value of a primitive, you'd see the actual value itself". The reason primitive values are always immutable is because whenever you change a primitive value, what you're actually doing is replacing the in-memory value. Because you can only replace the value and never modify it, by definition, that makes it immutable.
MDN summarizes this nicely.
"All primitives are immutable, i.e., they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered."
Before you leave
I know, "another newsletter pitch" - but hear me out. Most JavaScript newsletters are terrible. When's the last time you actually looked forward to getting one? Even worse, when's the last time you actually read one rather than just skim it?
We wanted to change that, which is why we created Bytes. The goal was to create a JavaScript newsletter that was both educational and entertaining. 101,884 subscribers and an almost 50% weekly open rate later, it looks like we did it.
Delivered to 101,884 developers every Monday

Sdu
@sduduzo_g
This is the first ever newsletter that I open a music playlist for and maximize my browser window just to read it in peace. Kudos to @uidotdev for great weekly content.

Brandon Bayer
@flybayer
The Bytes newsletter is a work of art! It's the only dev newsletter I'm subscribed too. They somehow take semi boring stuff and infuse it with just the right amount of comedy to make you chuckle.

John Hawley
@johnhawly
Bytes has been my favorite newsletter since its inception. It's my favorite thing I look forward to on Mondays. Goes great with a hot cup of coffee!

Garrett Green
@garrettgreen
I subscribe to A LOT of dev (especially JS/TS/Node) newsletters and Bytes by @uidotdev is always such a welcomed, enjoyable change of pace to most (funny, lighthearted, etc) but still comprehensive/useful.

Muhammad
@mhashim6_
Literally the only newsletter I’m waiting for every week.

Grayson Hicks
@graysonhicks
Bytes is the developer newsletter I most look forward to each week. Great balance of content and context! Thanks @uidotdev.

Mitchell Wright
@mitchellbwright
I know I've said it before, but @tylermcginnis doesn't miss with the Bytes email. If you're a developer, you really need to subscribe

Ali Spittel
@aspittel
Can I just say that I giggle every time I get the @uidotdev email each week? You should definitely subscribe.

Chris Finn
@thefinnomenon
Every JavaScript programmer should be subscribed to the newsletter from @uidotdev. Not only do they manage to succinctly cover the hot news in the JavaScript world for the week but it they manage to add a refreshing humor to it all.