Mateen Kiani
Published on Tue Jul 01 2025·5 min read
JavaScript is at the heart of modern web development, powering dynamic pages and interactive features. Yet developers often stumble on one fundamental question: how does JavaScript pass data between variables and functions? It’s easy to assume everything shares the same behavior, but there’s a hidden nuance in how primitives and objects get handled behind the scenes. So, does JavaScript pass by reference or value when you assign or pass variables?
JavaScript actually uses both strategies. Primitive types—like numbers, strings, and booleans—are passed by value, creating independent copies. Objects, arrays, and functions, on the other hand, are passed by value of the reference, which feels like pass-by-reference. Understanding this split helps you write safer code, avoid subtle bugs, and optimize performance.
In JavaScript, the primitive types are:
When you assign a primitive value, JavaScript copies the value into the new variable. That means changes to one variable don’t affect the other.
let a = 10;let b = a; // b gets its own copy: 10b = 20;console.log(a); // 10console.log(b); // 20
Here, a
remains 10 even after updating b
. This behavior is predictable. You can pass primitives into functions without worrying about side effects:
function increment(x) {x++;return x;}let num = 5;let newNum = increment(num);console.log(num); // 5console.log(newNum); // 6
Because x
is a copy, the original num
stays the same. This isolation reduces unexpected interactions and makes primitive operations straightforward.
Tip: Use primitives when you need immutable, independent values. This avoids accidental shared state.
Objects are more complex. When you assign or pass an object, JavaScript copies the reference value, not the actual object. Both variables then point to the same underlying structure.
let obj1 = { name: 'Alice' };let obj2 = obj1;obj2.name = 'Bob';console.log(obj1.name); // 'Bob'
Here, obj1
and obj2
share the same object. Changing a property via one variable affects the other. This is why some call it “pass by reference,” but technically it’s pass by value of the reference.
Under the hood, each object lives in the heap. Variables hold a pointer (address) to that location. When you copy the pointer, both variables refer to the same heap object.
Understanding this helps you decide when to clone objects or design immutable patterns.
Arrays and functions follow the same rule as objects. They live in the heap, so variable assignments copy the pointer, not the data.
let arr1 = [1, 2, 3];let arr2 = arr1;arr2.push(4);console.log(arr1); // [1, 2, 3, 4]function greet() {console.log('Hello');}let sayHi = greet;sayHi(); // 'Hello'
In the array example, modifying arr2
also modifies arr1
. For functions, copying the reference allows you to pass or store functions easily.
Note: You can use methods like
slice
,concat
, or spread ([...]
) to create shallow copies of arrays and avoid shared mutations.
Often you need a fresh copy of an object or array. Two approaches exist:
{ ...obj }
or [ ...arr ]
let original = { a: 1, nested: { b: 2 } };let copy = { ...original };copy.nested.b = 99;console.log(original.nested.b); // 99 (shared nested object)
js
let deep = JSON.parse(JSON.stringify(original));
js
let deep2 = structuredClone(original);
Caution:
JSON
approach drops functions,undefined
, and symbols. Use libraries like Lodash’scloneDeep
for robust deep cloning.
Knowing pass-by behavior prevents bugs. Here are tips:
// Bad practicefunction updateUser(user) {user.isAdmin = true; // mutates original}// Better practicefunction promoteUser(user) {return { ...user, isAdmin: true };}
Following these patterns leads to safer and more maintainable code.
In JavaScript, primitives are passed by value, giving you independent copies and fewer side effects. Objects, arrays, and functions are passed by the value of their reference, which can feel like pass-by-reference. Recognizing this split is key to writing bug-free code.
Whenever you work with objects or arrays, ask yourself:
By applying clear cloning strategies and embracing immutability, you’ll avoid common pitfalls and make your code more predictable. Now you can confidently decide when to share a reference and when to isolate data.
"Understanding how JavaScript passes data is like having a map in unfamiliar territory—it guides you to safer, more efficient code."
Internal Resource: Learn more about JavaScript objects in this developers guide on JavaScript objects.