Suggest an editImprove this articleRefine the answer for “Primitives and objects in memory”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Primitives live on the stack and are copied by value, while objects live on the heap and only a reference to them is kept on the stack, so it is the reference that gets copied.** That is why two variables holding primitives are fully independent, while two variables holding one object observe the same changes. Spread (`{ ...obj }`, `[...arr]`) produces a new reference only at the top level, nested objects stay shared, so a fully independent copy needs `structuredClone()`. ```javascript let a = 10; let b = a; // the value is copied b = 20; console.log(a); // 10 const user1 = { name: 'Tim' }; const user2 = user1; // the reference is copied user2.name = 'Alex'; console.log(user1.name); // "Alex" ``` **Key point:** the stack holds values and references, the heap holds the objects themselves, so copying a variable that holds an object copies the pointer, not the data.Shown above the full answer for quick recall.Answer (EN)Image**JavaScript keeps data in two places in memory: the stack holds primitives, while the heap holds objects and the stack only holds a reference to them.** That is exactly why a primitive is copied by value and an object is copied by reference. ## Theory ### TL;DR - The stack is fast memory for primitives and for references to objects. - The heap is flexible memory where the objects themselves live: objects, arrays, functions, `Date`, `Map`, `Set`. - A primitive is copied by value: the new variable owns its own copy of the data. - An object is copied by reference: both variables look at the same region of the heap. - Spread breaks the reference only at the top level; nested structures need a deep copy (`structuredClone()`). ### Quick example ```javascript // primitive: the value is copied let a = 10; let b = a; b = 20; console.log(a, b); // 10 20 // object: the reference is copied const user1 = { name: 'Tim' }; const user2 = user1; user2.name = 'Alex'; console.log(user1.name, user2.name); // "Alex" "Alex" ``` ### Primitives: the stack and copying by value Primitives are `string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`. They are stored **on the stack**, a fast region of memory that holds the values themselves rather than references. ```javascript let a = 10; let b = a; // the value 10 is copied b = 20; console.log(a); // 10 console.log(b); // 20 ``` In memory (stack): ```text +---------------+ | a = 10 | | b = 20 | <- a separate copy +---------------+ ``` Every variable stores **its own value**, so a change in one does not affect the other. ### Objects: the heap and copying by reference Objects, and with them arrays, functions, dates and other complex structures, are stored **on the heap**, the memory area for "flexible" structures. The **stack** holds only a **reference (a pointer)** to that object. ```javascript const user1 = { name: 'Tim' }; const user2 = user1; // the reference (the pointer) is copied user2.name = 'Alex'; console.log(user1.name); // "Alex" ``` In memory: ```text STACK HEAP +---------------+ +----------------------+ | user1 --+ | | { name: "Alex" } | | user2 --+---------> +----------------------+ +---------------+ ``` Both variables point at one and the same object, so a change made through `user2` shows up in `user1`. ### A shallow copy and why it does not save nested objects Dedicated copying techniques create **a new reference**: ```javascript const arr1 = [1, 2, 3]; const arr2 = [...arr1]; // the spread operator arr2.push(4); console.log(arr1); // [1, 2, 3] console.log(arr2); // [1, 2, 3, 4] ``` In memory: ```text arr1 --> [1, 2, 3] arr2 --> [1, 2, 3, 4] ``` Different references, so the changes do not touch the original. But when the object is nested, spread makes only a **shallow copy**: ```javascript const user1 = { name: 'Tim', address: { city: 'Kyiv' } }; const user2 = { ...user1 }; user2.address.city = 'London'; console.log(user1.address.city); // "London" ``` Why that happens: ```text user1.address --+ user2.address --+--> they point at the same inner object ``` In other words, the inner objects are **still copied by reference**. ### Deep copying To create **a fully independent copy** you have to break every reference inside. The old way: ```javascript const user1 = { name: 'Tim', address: { city: 'Kyiv' } }; const user2 = JSON.parse(JSON.stringify(user1)); user2.address.city = 'Berlin'; console.log(user1.address.city); // "Kyiv" ``` The modern way (Node.js 17+ and browsers from roughly 2022): ```javascript const user2 = structuredClone(user1); ``` `structuredClone()` produces a **deep copy** and leaves no shared references at all. ### Stack vs heap and the summary table ```text STACK (fast memory) ------------------------ a = 5 b = "Hello" user -> (a reference to an object) HEAP (flexible memory) ------------------------ { name: "Tim", age: 25 } ``` The stack stores simple values and references, while the heap stores the complex objects themselves. An everyday analogy: - **A primitive** is like a sheet of paper with a number on it: make a copy and you get another sheet, and changing the number on it leaves the original intact. - **An object** is like a folder of documents: if you hand a colleague a link to *the same* folder, you both see the same files. | Data type | Where it is stored | How it is copied | What is passed | | --- | --- | --- | --- | | Primitives (`string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) | Stack | By value | The value itself | | Objects (`object`, `array`, `function`, `Date`, `Map`, `Set`) | Heap | By reference | A pointer to the object | In short: - Primitives are copied **by value**, a new copy is created. - Objects are copied **by reference**, both variables "look at" the same region of memory. - For an independent copy of an object use `structuredClone()`, `JSON.parse(JSON.stringify(obj))` or `lodash.cloneDeep()`. ### Common mistakes - Assuming `[...arr]` or `{ ...obj }` gives a full copy. They copy only the top level. - Believing `const` makes an object immutable. `const` pins the reference, not the contents of the heap. - Applying `JSON.parse(JSON.stringify(obj))` to anything at all: it drops `undefined`, functions and `Symbol`, turns a `Date` into a string and throws on circular references. - Forgetting that strings in JavaScript are immutable: `str[0] = 'X'` changes nothing, because a primitive cannot be edited in place. - Expecting a large object to be freed the moment you assign `null` to one of the variables. While at least one live reference remains, the garbage collector will not reclaim it.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.