Primitive vs Reference Types in JS: Full Guide
Primitives are copied by value. Objects are copied by reference. Learn the critical difference, see it in action, and avoid the most common copy-and-mutate bug in JavaScript.
Primitive vs reference JavaScript values behave in two fundamentally different ways when you assign them to variables or pass them to functions: primitives are copied by value, and objects are copied by reference. Understanding this distinction prevents one of the most common and confusing bugs in the language.
| Behavior | Primitive types | Reference types |
|---|---|---|
| Copied by | Value | Reference |
| Examples | string, number, boolean, null, undefined, symbol, bigint | Object, Array, Function, Date, Map, Set |
| Changing a copy | Does not affect original | Affects original |
| Comparison | Compares values | Compares references (memory location) |
| Storage | Directly in the variable | Variable stores a pointer to the object |
How Primitives Work: Copy by Value
When you assign a primitive value to a new variable, JavaScript creates a fresh copy of that value. The two variables are completely independent. Changing one has no effect on the other.
let color = "blue";
let favoriteColor = color;
favoriteColor = "green";
console.log(color); // "blue"
console.log(favoriteColor); // "green"The variable favoriteColor received a copy of the value "blue", not a link to the original variable. When favoriteColor was reassigned to "green", the original color variable remained untouched. This is intuitive behavior that matches how most people expect variables to work.
Primitives also compare by value. Two primitives are equal if they contain the same data, regardless of where they came from:
let a = 100;
let b = 100;
console.log(a === b); // true (same value)
let x = "hello";
let y = "hello";
console.log(x === y); // true (same value)How Objects Work: Copy by Reference
When you assign an object to a new variable, JavaScript does not create a copy of the object. Instead, both variables point to the same object in memory. Changes through one variable are visible through the other.
let user = { name: "Alex", score: 0 };
let player = user;
player.score = 100;
console.log(user.score); // 100 (also changed!)The variable player did not receive a copy of the object. It received a reference to the same object that user points to. When you modify player.score, you are modifying the single shared object, so user.score also reflects the change.
Both variables point to the same object in memory. There is only one object, with two names that can reach it. This is why modifying the object through one name affects what you see through the other.
Objects also compare by reference, not by value. Two objects with identical contents are not equal because they occupy different memory locations:
let obj1 = { value: 10 };
let obj2 = { value: 10 };
console.log(obj1 === obj2); // false (different objects in memory)
let obj3 = obj1;
console.log(obj1 === obj3); // true (same object in memory)This is a frequent source of confusion. Two objects that look identical are not equal unless they are literally the same object.
Arrays Are Reference Types Too
Arrays are objects in JavaScript, so they follow the same reference behavior. Assigning an array to a new variable shares the array, it does not copy it.
let numbers = [1, 2, 3];
let copy = numbers;
copy.push(4);
console.log(numbers); // [1, 2, 3, 4]
console.log(copy); // [1, 2, 3, 4]The push method modified the shared array, visible through both variables. If you need an independent copy of an array, use the spread operator to create a new array with the same elements:
let numbers = [1, 2, 3];
let realCopy = [...numbers];
realCopy.push(4);
console.log(numbers); // [1, 2, 3] (unchanged)
console.log(realCopy); // [1, 2, 3, 4]The spread operator creates a brand new array, so mutations to realCopy do not affect the original numbers.
Functions and Reference Types
When you pass an object to a function, the function receives a reference to the same object, not a copy. This means a function can modify the original object.
function addPoint(player) {
player.score += 1;
}
let user = { name: "Alex", score: 0 };
addPoint(user);
console.log(user.score); // 1The addPoint function modified the original object because it received a reference. This is intentional and useful: it allows functions to operate on shared data without returning and reassigning values. But it also means you must be careful not to accidentally mutate objects you did not intend to change.
Primitives passed to functions are safe from this. The function receives a copy of the value, so the original is never affected:
function increment(n) {
n += 1;
return n;
}
let count = 5;
let result = increment(count);
console.log(count); // 5 (unchanged)
console.log(result); // 6How to Copy Objects Safely
To create an independent copy of an object, you need to explicitly clone it. The spread operator creates a shallow copy, which works for objects with only primitive properties:
let original = { name: "Alex", score: 0 };
let clone = { ...original };
clone.score = 100;
console.log(original.score); // 0 (unchanged)For objects with nested objects, the spread operator only copies the top level. Nested objects are still shared by reference. For a complete deep copy, use structuredClone, which is available in all modern browsers and Node.js:
let original = { user: { name: "Alex" }, scores: [1, 2, 3] };
let deepCopy = structuredClone(original);
deepCopy.user.name = "Jordan";
console.log(original.user.name); // "Alex" (unchanged)For a deeper look at how JavaScript manages memory for these types, see the guide on how JavaScript stores primitive values in memory. For the complete list of data types, read the JavaScript data types guide.
Rune AI
Key Insights
- Primitives (string, number, boolean, etc.) are copied by value.
- Objects (arrays, plain objects, functions) are copied by reference.
- Changing a primitive copy never affects the original.
- Changing an object through one reference affects all references to it.
- Use spread syntax or structuredClone to create independent object copies.
Frequently Asked Questions
How do I copy an object without sharing the reference?
Are arrays primitive or reference types?
Why does changing a const object's property work?
Conclusion
Primitives are copied by value: changing one copy never affects the original. Objects are copied by reference: multiple variables can point to the same object in memory, and changes through one variable are visible through all of them. This is the single most important behavioral difference in the JavaScript type system.
More in this topic
Is JavaScript Frontend or Backend? Full Guide
JavaScript is both a frontend and backend language. Learn the difference between browser JavaScript and Node.js, what each is used for, and which one you should learn first.
Learn JavaScript Step by Step Tutorial with Real Examples
Follow a hands-on tutorial that teaches JavaScript by building a real interactive page. Write your first variables, functions, and event listeners with examples you can run.
JavaScript Tutorial: Complete Beginner's Guide to Programming in 2025
A structured learning path for absolute beginners. Learn what to study first, how to practice, and which JavaScript concepts matter most when you are starting from zero.