
Primitive vs. Reference Types in JavaScript

This Article is Over Ten Years Old...
Things can and do move very quickly in tech, which means that tech-related articles go out of date almost as soon as they have been written and published. If you are looking for up-to-date technical advice or opinion, it is unlikely that you will find it on this page.
You may find that my recent articles are more relevant, and you are always welcome to drop me a line if you have a specific technical problem you are trying to solve.
Primitive values and reference types are one of those JavaScript fundamentals that quietly sit underneath a huge number of beginner bugs. You do not always hear the terminology first. More often, you meet the consequences.
Two arrays that look identical are somehow not equal. A copied object changes when another part of the code updates it. A string behaves nicely and independently whilst an object seems to spread changes further than expected.
All of that becomes easier to understand once you know which values are primitive and which are reference‑like structures.
Primitive Values are the Simpler Category
In everyday JavaScript, primitive values are the small, basic values that are not objects.
The main primitives are:
stringnumberbooleannullundefinedsymbolbigint
For most front‑end work, you spend the most time with the first five.
These values behave simply when assigned and compared. If you assign a primitive to another variable, you get a new independent variable holding that value.
let firstName = 'Sophie';let copiedName = firstName;copiedName = 'Ellie';console.log(firstName); // Sophieconsole.log(copiedName); // EllieChanging copiedName does not alter firstName.
Objects, Arrays, and Functions are Not Primitives
Arrays, plain objects, dates, and functions all belong to the object side of JavaScript.
That means they behave differently when assigned.
const originalUser = { name: 'Sophie',};const copiedUser = originalUser;copiedUser.name = 'Ellie';console.log(originalUser.name); // EllieThat surprises beginners because copiedUser sounds as if it should be a fresh copy. It is not. Both variables point to the same underlying object.
That is where the topic starts to matter. Primitive assignment feels like copying the value. Object assignment feels like sharing access to the same thing.
Equality Behaves Differently Too
One of the cleanest ways to see the distinction is with equality.
Primitives compare by value:
console.log(5 === 5); // trueconsole.log('hello' === 'hello'); // trueObjects compare by identity:
console.log({ name: 'Sophie' } === { name: 'Sophie' }); // falseconsole.log([1, 2, 3] === [1, 2, 3]); // falseThose objects and arrays look identical structurally, but they are separate instances, so strict equality returns false.
This is one of the first places where developers realise that objects in JavaScript are not compared the same way as strings or numbers.
Why Arrays Behave Like Objects
Arrays often feel like a middle case to beginners because they hold lists of values and look simple on the surface. But arrays are still objects in JavaScript.
That means they share the same broad rules:
- assigning an array does not clone it
- strict equality checks whether it is the same array instance
- mutating through one reference affects all references to that array
const originalItems = ['a', 'b'];const copiedItems = originalItems;copiedItems.push('c');console.log(originalItems); // ['a', 'b', 'c']Once you understand that arrays live on the object side of the line, this behaviour is much less surprising.
Strings are Primitive, Even Though They Have Methods
This is a small detail that catches some developers.
Strings are primitive values, but JavaScript still lets you call methods on them:
const title = 'checkout';console.log(title.toUpperCase());That can make strings feel object‑like. They are still primitives. The language simply gives them access to useful methods in a way that feels object‑oriented.
For most day‑to‑day work, the important thing is not the deeper implementation detail. It is remembering that strings do not share mutable state the way objects and arrays do.
Reference Types Create Shared‑State Bugs
When developers say "reference type bugs", they usually mean problems caused by several variables or parts of the application pointing to the same object unexpectedly.
For example:
const settings = { theme: 'dark',};const nextSettings = settings;nextSettings.theme = 'light';If you expected settings to remain unchanged, you now have a bug. Not because JavaScript misbehaved, but because the object was shared rather than copied.
It is also why object copying patterns matter so much in front‑end work, especially once state becomes more central to the application.
Copying an Object is Not the Same as Assigning It
If you need a separate top‑level object, you have to create one deliberately.
const settings = { theme: 'dark',};const nextSettings = { ...settings,};Now the two top‑level objects are different instances.
The same applies to arrays:
const items = ['a', 'b'];const nextItems = [...items];That said, these are shallow copies. Nested objects can still be shared. That is another important practical detail, but even recognising the top‑level primitive versus reference distinction gets you a long way.
This Affects Function Arguments as Well
The primitive versus reference distinction shows up very clearly when values move into functions.
const updateName = (name: string): void => { name = 'Ellie';};const updateUser = (user: { name: string }): void => { user.name = 'Ellie';};The string example only changes the local parameter variable. The object example mutates the shared object, which is why object arguments often create visible side effects outside the function whilst primitive arguments usually do not.
Why This Matters in Real Front‑End Code
This is not just academic language trivia. The primitive‑versus‑reference split affects:
- state updates
- equality checks
- memoisation
- function side effects
- debugging strange data changes
If you are comparing values, copying data, or updating UI state, you are already relying on these rules whether you think about them explicitly or not.
It is worth learning this early. It saves a lot of confusion later when codebases get more complex.
A Useful Question to Ask
When something behaves strangely, ask:
"Am I working with a simple value, or am I working with an object‑like structure that might be shared?"
That question often points you to the bug faster than staring at the syntax alone.
Wrapping up
Primitive values and reference types differ mainly in how they are copied, compared, and mutated. Primitives such as strings and numbers behave like independent values. Objects and arrays behave like shared structures unless you create a new copy deliberately. Once that distinction is clear, a lot of common JavaScript behaviour becomes much easier to reason about.
Key Takeaways
- Strings, numbers, booleans,
null, andundefinedare primitive values. - Objects, arrays, and functions live on the object side of JavaScript and can be shared by reference.
- Primitive assignment creates an independent value relationship; object assignment creates shared access to the same underlying object.
- Strict equality compares primitives by value but objects by identity.
- Many front‑end state bugs come from treating objects as though assignment copied them automatically.
Once you understand which side of that line a value lives on, a lot of JavaScript stops feeling inconsistent and starts feeling predictable.
Related Articles

Lifting State up in React. 
Pass by Value vs. Reference in JavaScript. Pass by Value vs. Reference in JavaScript

Positioning in CSS. Positioning in CSS

Classes in JavaScript: An Introduction. Classes in JavaScript: An Introduction

JavaScript Array Manipulation: slice() vs. splice(). JavaScript Array Manipulation:
slice()vs.splice()
What Does Front‑End Development Mean? What Does Front‑End Development Mean?

Return the Length of Arguments Passed in JavaScript. Return the Length of Arguments Passed in JavaScript

Use JavaScript to Find the Week Day from a Date. Use JavaScript to Find the Week Day from a Date

Is a Software Engineer High Paying? Is a Software Engineer High Paying?

Toggle a Boolean in JavaScript. Toggle a Boolean in JavaScript

The CSS overflow Property. The CSS
overflowProperty
Position: sticky in CSS. position: stickyin CSS