A Journey to the Center of JavaScript

Primitive Values and Reference Values

Çağlayan Yanıkoğlu
Jotform Tech
Published in
5 min readFeb 18, 2023

This week’s #SundayTechMusings is about one of the most feared topics in JavaScript: advanced js. I often see people who are new to front-end development start coding in React or some similar framework. They don’t know enough js but are trying to learn React. I believe this is a huge mistake.

I always tell my students to learn JavaScript first. My sincere advice is that they should learn the logic of code, not copy-paste it. Copying and pasting might solve your problem, but if you don’t understand what you’re doing, it can be very hard to fix any problems that occur.

Understanding how JavaScript works is very important. If you know JavaScript logic, you can easily learn any framework. But a lot of new programmers focus on advanced topics without learning the basics.

In many interviews I conduct with front-end developers, these topics are difficult for candidates. In this series of posts, we’ll look at the most advanced, difficult-to-learn topics, and I will try to explain them in a very basic and simple way.

I’ll divide topics among a few posts. In this first post, we’ll look at primitive values and reference values.

Other topics will include:

  • Hoisting
  • Closures
  • IIFE
  • Inheritance and prototype chain
  • JavaScript engine and runtime
  • Asynchronous JavaScript and event loop (my favorite part)
  • .call(), .apply(), .bind()
  • ‘this’ keyword

1-) Primitive types and reference types

There are a lot of types used to define variables in js (string, number, array, object, etc.). Unlike in other programming languages, in JavaScript, you don’t have to declare this type.

You may think that all value types behave similarly, but we can separate them into:

  • Primitive types: string, number, Boolean, undefined, etc.
  • Reference types: array, object, function (anything that is “typeof” object)

What are the differences between primitive and reference types?

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 (27, 'Caglayan', 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).

For example, let’s say we create a variable called name and assign the string Joe to it. Then we create a new variable called copyNaand assign it to whatever the in-memory value name is, which happens to be Joe. From there, we change the in-memory value copyName to be David. Now, when we log copyName we get David , and when we log name we get Joe.

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.

First, we create a variable called user and assign it to an object that has two properties, name and age. Then we create a new variable called copyUser and assign it to whatever the in-memory value of user is, which is the reference to the spot in memory where the user object is located.

At this point, both user and copyUser are referencing the same spot in memory. So when we modify copyUser.name, because user and copyUser are referencing the same spot in memory, it’s as if we also modified user.name. That’s why when we log user.name and copyUser.name we get the same value, David.

Let’s look at one more example to cement your understanding. What do you think happens when we use the identity operator (===), to compare two primitives that have the same value.

Here, we see that because name and friend have the same value, Joewhen 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 Joe, comparing them evaluates to true.

Now, what about reference values?

Even though user and anotherUser 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 user and anotherUser 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.
Even two empty objects are not equal, as you can see in line 13.

Figure 1: Primitive Types vs Reference Types
Figure 2: Stack vs heap

In the above Figure 2, js stores primitive values in Stack. But it stores reference values in Heap. Object reference addresses are stored in the stack but their values store in the heap.

An interesting by-product of primitive values is that they’re always immutable. This makes 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, that makes it immutable by definition..

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.”

To sum up, my advice is if you are dealing with objects, you have to be very careful. Because when you think you copy the object, you may corrupt the original data. If you work with copy objects, you have to use shallow or deep copy methods.

This was the first post in this series on advanced JavaScript. If you’re interested, you can follow me on GitHub, Twitter, or LinkedIn to catch more on these topics.

If you find this content helpful and would like to show your support, you can buy me a beer🍺😊
Buy Beer🍺

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in Jotform Tech

Welcome to Jotform official tech blog. Read about software engineering and how Jotform engineers build the easiest form builder.

Written by Çağlayan Yanıkoğlu

Team Lead / Senior Frontend Developer @Jotform. Frontend Instructor/Consultant @patika.dev, @kodluyoruz. https://superpeer.com/caglayandev

Responses (1)

Write a response