JavaScript Interview Prep
Type System & Coercion

Primitive vs Reference

Sticky Notes vs Business Cards

LinkedIn Hook

You copy an object in JavaScript and mutate the copy — but the original mutates too.

You pass a number to a function, change it, and the outer value stays the same. You pass an array, push one item, and suddenly the outer array has a new element.

Why? Because JavaScript has exactly 7 primitive types that live on the stack, and everything else is a reference type that lives on the heap.

When you assign a primitive, you copy the value. When you assign an object, you copy the pointer — not the data.

In this lesson you'll see the 7 primitives, the stack vs heap memory model, pass-by-value vs pass-by-sharing, and the exact shallow-copy and deep-copy patterns that avoid the most common mutation bug in JS interviews.

If you've ever been caught by obj2 = obj1 silently aliasing the same object — this lesson fixes that forever.

Read the full lesson -> [link]

#JavaScript #InterviewPrep #MemoryModel #StackVsHeap #Frontend #CodingInterview #WebDevelopment


Primitive vs Reference thumbnail


What You'll Learn

  • The 7 primitive types and how they differ from reference types
  • How the stack and heap store values — and why that matters for copying
  • Pass-by-value vs pass-by-sharing for function arguments, and how to make real independent copies

Sticky Notes vs Business Cards

Think of primitive values like sticky notes — each one holds its own value directly. When you copy a sticky note, you create a completely independent copy. Reference types are like business cards with an address on them — when you copy the card, both copies point to the same house.

The 7 Primitives

JavaScript has exactly 7 primitive types:

// 1. string
const name = "Rakibul";

// 2. number (integers and floats, both are "number")
const age = 25;
const price = 9.99;

// 3. boolean
const isActive = true;

// 4. null (intentional absence of value)
const data = null;

// 5. undefined (declared but not assigned)
let result;
console.log(result); // undefined

// 6. symbol (unique identifier -- ES2015)
const id = Symbol("id");

// 7. bigint (arbitrary-precision integers -- ES2020)
const huge = 9007199254740993n;

Reference Types

Everything that is not a primitive is an object (a reference type):

// Objects
const person = { name: "Rakibul", age: 25 };

// Arrays (special objects)
const colors = ["red", "green", "blue"];

// Functions (callable objects)
function greet() { return "Hello"; }

// Dates, RegExp, Map, Set, etc. -- all objects
const now = new Date();
const pattern = /hello/gi;

Stack vs Heap — Memory Model

Primitives are stored directly on the stack (fast, fixed-size). Reference types store a pointer on the stack that points to the actual data on the heap (dynamic, larger).

// PRIMITIVES -- stored on the stack, copied by value
let a = 10;
let b = a;    // b gets its OWN copy of the value 10
b = 20;
console.log(a); // 10 -- unchanged, they're independent

// REFERENCE TYPES -- pointer on stack, data on heap, copied by reference
let obj1 = { name: "Rakibul" };
let obj2 = obj1;  // obj2 gets a copy of the POINTER, not the object
obj2.name = "Karim";
console.log(obj1.name); // "Karim" -- BOTH point to the same object!

Proving Reference Behavior with Arrays

const arr1 = [1, 2, 3];
const arr2 = arr1;

arr2.push(4);
console.log(arr1); // [1, 2, 3, 4] -- same array in memory

// To create an independent copy:
const arr3 = [...arr1];         // shallow copy via spread
const arr4 = arr1.slice();      // shallow copy via slice
const arr5 = structuredClone(arr1); // deep copy (modern)

arr3.push(5);
console.log(arr1); // [1, 2, 3, 4] -- unaffected

Function Arguments — Same Rules Apply

// Primitive: pass by value
function increment(num) {
  num++;
  console.log("Inside:", num); // 11
}
let count = 10;
increment(count);
console.log("Outside:", count); // 10 -- unchanged

// Reference: pass by sharing (the reference is copied)
function addSkill(person) {
  person.skills.push("React");
}
const dev = { name: "Rakibul", skills: ["JS"] };
addSkill(dev);
console.log(dev.skills); // ["JS", "React"] -- mutated!

Primitive vs Reference visual 1


Common Mistakes

  • Assuming const obj = {...} makes the object immutable — const only locks the binding, not the contents. You can still mutate properties of a const object or array.
  • Using JSON.parse(JSON.stringify(obj)) as a universal deep clone — it silently drops functions, undefined, Symbol keys, and breaks Date/Map/Set. Prefer structuredClone(obj) for modern code.
  • Expecting the spread operator or Object.assign to clone nested objects — both do a shallow copy. Nested objects still share references with the original.

Interview Questions

Q: What are the 7 primitive types in JavaScript?

string, number, boolean, null, undefined, symbol, and bigint.

Q: What is the difference between primitive and reference types in terms of memory?

Primitives are stored directly on the stack and copied by value -- changing one copy doesn't affect the other. Reference types store a pointer on the stack that points to data on the heap -- copying the variable copies only the pointer, so both variables point to the same object.

Q: How do you create a true copy of an object?

For a shallow copy: spread operator ({...obj}), Object.assign({}, obj), or Array.prototype.slice(). For a deep copy: structuredClone(obj) (modern) or JSON.parse(JSON.stringify(obj)) (older, with limitations like losing functions and undefined).

Q: What is the difference between stack and heap memory?

The stack is fixed-size, fast, and stores primitives and pointers directly. The heap is dynamic, larger, and stores objects, arrays, and functions. Reference variables live on the stack but their data lives on the heap — which is why copying them only copies the pointer.

Q: How does copying a primitive differ from copying an object?

Copying a primitive duplicates the value, so the two variables are independent. Copying an object duplicates only the pointer, so both variables alias the same underlying object — mutating one mutates the other.

Q: What is structuredClone and when would you use it?

structuredClone is a built-in that produces a deep copy of almost any value, including nested objects, arrays, Date, Map, Set, and cyclic references. Use it whenever you need an independent deep copy and don't want the limitations of JSON.parse(JSON.stringify(...)).


Quick Reference — Cheat Sheet

PRIMITIVE vs REFERENCE -- QUICK MAP

7 Primitives (stored on STACK, copied by VALUE):
  string | number | boolean | null | undefined | symbol | bigint

Reference types (pointer on stack, data on HEAP, copied by REFERENCE):
  object | array | function | Date | RegExp | Map | Set | ...

Copy behavior:
  let b = a            -> primitives: independent copy
  let o2 = o1          -> objects: same pointer, shared data

Make real copies:
  Shallow:  {...obj}  |  Object.assign({}, obj)  |  arr.slice()
  Deep:     structuredClone(obj)   (preferred)
            JSON.parse(JSON.stringify(obj))  (drops fns/undefined/symbols)

Function args:
  Primitive -> pass by value (outer stays unchanged)
  Reference -> pass by sharing (outer mutates if you mutate props)

Previous: Array Methods -> The Functional Toolbox Next: Type Coercion -> The Overly Helpful Translator


This is Lesson 8.1 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.

On this page