Suggest an editImprove this articleRefine the answer for “Immutable and mutable data”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Mutable data can be changed after it is created, while immutable data cannot: instead of changing it, a new value is produced.** In JavaScript every primitive (`string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) is immutable, while objects, arrays, functions, `Map` and `Set` are mutable. `const` does not help here: it forbids reassigning the reference, but it does not forbid editing the object that reference points at. To freeze an object you need `Object.freeze()`, and nested structures need a recursive deep freeze. ```javascript let a = 'Hello'; a[0] = 'J'; console.log(a); // "Hello", the string is immutable const user = { name: 'Tim' }; user.name = 'Alex'; console.log(user); // { name: 'Alex' }, the object is mutable ``` **Key point:** primitives are immutable, objects are mutable, and immutability makes state predictable, which is why React and Redux are built on it.Shown above the full answer for quick recall.Answer (EN)Image**Mutable data can be changed after it has been created, while immutable data cannot be changed: a new value is produced instead.** In JavaScript primitives are immutable, while objects, arrays and functions are mutable. ## Theory ### TL;DR - **Mutable**: the object can be edited after creation: `object`, `array`, `function`, `Map`, `Set`. - **Immutable**: the value cannot be edited, only a new one can be created: every primitive. - `const` pins the reference, not the contents of the object, so `const user = {}` still allows `user.name = '...'`. - "Changing" a string or a number always creates a new value, the old one stays untouched. - `Object.freeze()` makes an object immutable at the top level, nested ones need a deep freeze. ### Quick example ```javascript // mutable const user = { name: 'Tim' }; user.name = 'Alex'; console.log(user); // { name: 'Alex' } // immutable let a = 'Hello'; a[0] = 'J'; console.log(a); // "Hello", nothing changed ``` ### Definitions | Term | Meaning | The essence | | --- | --- | --- | | **Mutable** | *changeable* | an object that can be modified after it is created | | **Immutable** | *unchangeable* | data that cannot be modified, you can only create new data | ### Mutable data **Objects and arrays** in JavaScript are mutable structures. ```javascript const user = { name: 'Tim' }; user.name = 'Alex'; // we modify the object console.log(user); // { name: 'Alex' } ``` Even though `user` is declared with `const`, **its contents (the object)** can be modified, because `const` forbids changing the **reference** itself, not the data it points at. The same goes for an array: ```javascript const numbers = [1, 2, 3]; numbers.push(4); console.log(numbers); // [1, 2, 3, 4] ``` Arrays are **mutable**, since we can add, remove and change elements. ### Immutable data **Primitives** in JavaScript are immutable. They are: `string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`. ```javascript let a = 'Hello'; a[0] = 'J'; // an attempt to modify the string console.log(a); // "Hello", unchanged ``` Strings are **immutable**: "changing" one creates a new string. The same with numbers: ```javascript let x = 5; let y = x; y = y + 1; console.log(x); // 5 console.log(y); // 6 ``` Numbers are immutable too, they cannot be "changed", only a new value can be created. How that looks in memory: | Data type | Mutability | Where it is stored | Behaviour | | --- | --- | --- | --- | | Primitive (`string`, `number`, `boolean` and others) | **Immutable** | Stack | a new value is created on "change" | | Object, array, function | **Mutable** | Heap | modified through the reference | ```javascript let name = 'Ann'; name = name + 'a'; ``` ```text STACK: +------------------+ | name = "Ann" | <- the old string | name = "Anna" | <- the new string (created from scratch) +------------------+ ``` The string `"Ann"` is not modified, a new string `"Anna"` is created. ### Why it matters First, the behaviour on copying: ```javascript const user1 = { name: 'Tim' }; const user2 = user1; user2.name = 'Alex'; console.log(user1.name); // "Alex", both changed (mutable) ``` Second, reactive frameworks (React, Redux, Vue and others). Immutability is a key principle there: - it lets you **track state changes** by comparing references; - it makes **undo/redo** straightforward; - it makes the code **more predictable**. An example of the React approach: ```javascript // bad (mutating the state directly) state.user.age++; // good (an immutable update) setState({ ...state, user: { ...state.user, age: state.user.age + 1 } }); ``` ### How to make an object immutable by hand ```javascript const user = Object.freeze({ name: 'Tim', age: 25 }); user.age = 30; // will not work console.log(user.age); // 25 ``` `Object.freeze()` makes an object **immutable** at the top level. Nested properties have to be "deeply frozen": ```javascript function deepFreeze(obj) { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object' && obj[key] !== null) { deepFreeze(obj[key]); } }); return Object.freeze(obj); } const data = deepFreeze({ user: { name: 'Tim', skills: ['JS'] } }); data.user.name = 'Alex'; // will not change ``` The summary table: | Category | Examples | Mutability | Behaviour | | --- | --- | --- | --- | | **Immutable** | `string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint` | cannot be changed | a new copy is created | | **Mutable** | `object`, `array`, `function`, `Map`, `Set` | can be changed | modified "in place" | In short: - **Immutable**: cannot be changed, only a new value can be created. - **Mutable**: can be changed "in place". - Primitives are immutable, objects and arrays are mutable. - Immutability makes code more reliable, especially in React and Redux. ### Common mistakes - Confusing `const` with immutability. `const` is about reassigning the variable, not about the contents of the object. - Assuming `Object.freeze()` protects the whole structure. It is shallow, nested objects stay mutable. - Not noticing that in non-strict mode a write to a frozen object is silently ignored, while under `'use strict'` it throws a `TypeError`. - Mutating state in React (`state.items.push(x)`) and then wondering why the component did not re-render: a reference comparison sees no difference. - Believing array methods are immutable. `push`, `splice`, `sort` and `reverse` mutate the original; the immutable counterparts are `concat`, `slice`, `toSorted` and `toReversed`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.