Mutability refers to whether a data type can be changed after it's created:
| Data Type | Mutable | Immutable | Example |
|---|---|---|---|
| Number | ❌ | ✅ | 42, 3.14 |
| String | ❌ | ✅ | "hello", 'world' |
| Boolean | ❌ | ✅ | true, false |
| Undefined | ❌ | ✅ | undefined |
| Null | ❌ | ✅ | null |
| Symbol | ❌ | ✅ | Symbol('id') |
| BigInt | ❌ | ✅ | 123n |
| Object | ✅ | ❌ | {name: "John"} |
| Array | ✅ | ❌ | [1, 2, 3] |
| Function | ✅ | ❌ | function() {} |
Primitive = Immutable
Non-Primitive (Object, Array, Function) = Mutable
When we say primitives are immutable, it means the value itself cannot be changed. You can reassign the variable, but you're not changing the original value.
// ✅ This is reassignment (creating a new value)
let message = "Hello";
message = "Hi there"; // Creates new string, doesn't change "Hello"
// ❌ This would be mutation (if it were possible)
message[0] = "h"; // This doesn't work! Strings can't be mutated
console.log(message); // Still "Hi there"// Numbers
let age = 25;
age = 26; // New number created, 25 is unchanged
// Booleans
let isActive = true;
isActive = false; // New boolean created, true is unchanged
// Strings
let name = "Alice";
name = name.toUpperCase(); // Creates "ALICE", doesn't change "Alice"const person = {
name: "John",
age: 30
};
// ✅ This mutates the object
person.name = "Jane"; // Changes the property
person.city = "New York"; // Adds new property
delete person.age; // Removes property
console.log(person); // { name: "Jane", city: "New York" }const fruits = ["apple", "banana"];
// ✅ These mutate the array
fruits.push("orange"); // Adds element
fruits[0] = "grape"; // Changes element
fruits.pop(); // Removes element
console.log(fruits); // ["grape", "banana"]function greet() {
return "Hello";
}
// ✅ This mutates the function object
greet.customProperty = "I'm a function!";
console.log(greet.customProperty); // "I'm a function!"const Makes Everything Immutable// ❌ Common misconception
const numbers = [1, 2, 3];
numbers.push(4); // This works! Array is still mutable
console.log(numbers); // [1, 2, 3, 4]
// ✅ const prevents reassignment, not mutation
// numbers = [5, 6, 7]; // This would cause an error// ❌ This doesn't work
let text = "hello";
text[0] = "H"; // Fails silently or throws error in strict mode
console.log(text); // Still "hello"
// ✅ Create a new string instead
text = "H" + text.slice(1);
console.log(text); // "Hello"// When you want to "change" a primitive, create a new one
let score = 100;
score = score + 10; // Creates new number: 110
let message = "Hello";
message = message + " World"; // Creates new string: "Hello World"// Objects: Change properties directly
const user = { name: "Alice", points: 100 };
user.points += 10; // Mutates the object
user.level = "Pro"; // Adds new property
// Arrays: Use methods that modify the array
const tasks = ["eat", "sleep"];
tasks.push("code"); // Mutates array
tasks[0] = "wake up"; // Mutates arrayUnderstanding mutability helps you:
// What happens here?
const obj = { count: 1 };
const newObj = obj;
newObj.count = 2;
console.log(obj.count); // What will this show?
console.log(newObj.count); // What will this show?
// Answer: Both show 2! Objects are mutable and both variables
// reference the same object in memory.// What about this?
let str1 = "hello";
let str2 = str1;
str2 = "world";
console.log(str1); // What will this show?
console.log(str2); // What will this show?
// Answer: str1 shows "hello", str2 shows "world"
// Strings are immutable, so str2 gets a new string value