Skip to content

Beginner · Arrays and objects · topic 20 of 61 · 25 min

References, copies and equality

Explanation

Variables hold objects and arrays by reference: two names can point to the same object, and === compares whether they are the same object, not whether they look alike. Spread and Object.assign make shallow copies; structuredClone makes deep copies. Knowing this prevents "it changed by itself" bugs.

Values versus references

A primitive (number, string, boolean…) is stored as the value itself. An object or array is stored somewhere in memory, and the variable holds a reference: a pointer to where it lives. Assigning an object to another variable copies the reference, not the object.

javascript
const original = { qty: 1 };
const alias = original;     // same object, two names
alias.qty = 5;
console.log(original.qty);  // 5
Think of it like this: A reference is like a Google Maps location pin you share on WhatsApp. Sending it to five friends does not build five houses; everyone gets directions to the same house. If one friend paints the gate, everyone who visits sees the new colour.

=== compares identity for objects

javascript
console.log([1, 2] === [1, 2]);   // false: two different arrays
const a = { x: 1 };
const b = a;
console.log(a === b);             // true: the same object
console.log(JSON.stringify({ x: 1 }) === JSON.stringify({ x: 1 })); // true (compares content, key order matters)
To compare content, compare the fields you care about, or use a helper.

Functions receive references too

Passing an object to a function passes the reference. If the function changes the object, the caller sees the change. This is called mutation, and unexpected mutation is one of the most common bugs in real projects.

javascript
function addFreeGift(cart) {
  cart.push('free keychain');   // mutates the caller's array
  return cart;
}
const myCart = ['shoes'];
addFreeGift(myCart);
console.log(myCart); // ['shoes', 'free keychain'] (changed!)

Shallow copies

Spread ([...arr], {...obj}), Object.assign({}, obj), arr.slice() and Array.from(arr) make a shallow copy: a new outer array or object, but nested objects inside are still shared references.

javascript
const order = { id: 1, address: { city: 'Pune' } };
const copy = { ...order };
copy.id = 2;                 // fine: id is a primitive in the new object
copy.address.city = 'Nashik'; // changes the SHARED nested object!
console.log(order.address.city); // 'Nashik'

Deep copies with structuredClone

A deep copy duplicates every level. structuredClone(value) is built into modern browsers and Node.js 17+. It handles nested objects, arrays, Dates, Maps and Sets, but not functions or class methods.

javascript
const deep = structuredClone(order);
deep.address.city = 'Thane';
console.log(order.address.city); // 'Nashik' (unchanged this time)
Careful: The old trick JSON.parse(JSON.stringify(obj)) also deep-copies, but it silently breaks data: Dates become strings, undefined values and functions vanish, Map and Set become {}, and NaN becomes null. Prefer structuredClone.

Object.freeze

Object.freeze(obj) stops changes to an object's own properties (in strict mode a change throws; otherwise it is ignored). The freeze is shallow: nested objects can still change. It is useful for constants such as configuration.

javascript
'use strict';
const CONFIG = Object.freeze({ gst: 18, limits: { cod: 50000 } });
// CONFIG.gst = 5;          // TypeError in strict mode
CONFIG.limits.cod = 1;      // allowed: freeze is shallow
Tip: Default habit: functions should not change their inputs. Return a new array or object instead ([...list, item], { ...obj, key: value }). Your future self debugging at 2 a.m. will thank you.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

References, copies and equality · 1/6

References and copies

In this lesson you will learn why objects sometimes change "by themselves", and how to copy them safely.

Prefer a video by a teacher? Find free videos on “javascript reference vs value shallow copy deep copy structuredClone” on YouTube ↗

In real life: The "discount applied twice" bug

A developer at an online store reused one product object for both the listing page and the cart. The cart code applied a discount by changing product.price directly, so the listing page also showed the reduced price and then discounted it again at checkout. The fix was to copy the product before changing it.

javascript
const product = { name: 'Lamp', price: 1000 };
const cartItem = { ...product, price: product.price * 0.9 };
console.log(product.price, cartItem.price); // 1000 900

Practice (0/3 done)

Task 1 · Code · Javascript

addItem(cart, item) currently changes the caller's array. Make it return a NEW array with the item added, leaving the original unchanged.

Task 2 · Code · Javascript

Write moveOrder(order, newCity) that returns a copy of order with address.city changed. The original order, INCLUDING its nested address, must not change.

Task 3 · Code · Javascript

Write sameItems(a, b) that returns true when two arrays of primitives have the same items in the same order (=== on the arrays is not enough).

Quick quiz

Question 1

1.const a = [1]; const b = a; b.push(2); What is a?

Question 2

2.What does { x: 1 } === { x: 1 } give?

Question 3

3.const o = { inner: { n: 1 } }; const c = { ...o }; c.inner.n = 2; What is o.inner.n?

Question 4

4.Which makes a deep copy that keeps Dates as Dates?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

const a = [1]; const b = a; b.push(2); What is a?

Answer: [1, 2]

a and b refer to the same array.

What does { x: 1 } === { x: 1 } give?

Answer: false

They are two different objects, so the references differ.

const o = { inner: { n: 1 } }; const c = { ...o }; c.inner.n = 2; What is o.inner.n?

Answer: 2

Spread is shallow: inner is shared.

Which makes a deep copy that keeps Dates as Dates?

Answer: structuredClone(obj)

structuredClone copies every level and supports Dates, Maps and Sets.

What is wrong with: const std::string& name() { std::string s = "Asha"; return s; }Related

Answer: It returns a reference to a local that is destroyed: a dangling reference

s dies when the function returns. Return std::string by value.

From References: another name for a variable

Assigning one class variable to another...Related

Answer: Copies the reference, so both refer to the same object

Classes are reference types.

From Structs, value types and reference types

What does Object.entries({ a: 1, b: 2 }) return?Related

Answer: [['a', 1], ['b', 2]]

entries gives an array of [key, value] pairs. keys gives only the keys and values only the values.

From Objects in depth

What does == compare for two record objects?Related

Answer: Their property values

Records generate value-based equality.

From Records and pattern matching

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Arrays and objects”. The module exam comes next.
  2. Module 4 exam: Arrays and objects · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Scope, this, prototypes and classes. 61 topics left in the course before the final exam.

← Previous: Destructuring, spread and rest