Immutability in functions
Immutability is the principle that data is not changed after it is created, and inside functions it means one rule: do not mutate the arguments, return a new value instead. It is one of the key principles behind pure, predictable functions: if a function changes an array or object it was given, it affects external state and becomes impure.
Theory
TL;DR
- Immutability means data is not changed after it is created.
- For functions the rule reads: do not mutate the arguments, return a new structure.
- Mutating arguments is a side effect: the caller's data changes invisibly.
- Immutable tools:
map,filter,concat, spread for arrays and{ ...obj }for objects. - Mutable operations avoided in pure functions:
push,pop,splice,sort,reverse, direct field assignment. - Strings in JavaScript are always immutable, they cannot be changed in place.
Quick example
javascript
// mutable: changes the caller's array
function addItemMutable(arr, item) {
arr.push(item);
return arr;
}
// immutable: returns a new array
function addItem(arr, item) {
return [...arr, item];
}
const numbers = [1, 2, 3];
console.log(addItem(numbers, 4)); // [1, 2, 3, 4]
console.log(numbers); // [1, 2, 3], the source is intactMutation versus a new copy
The mutable approach changes what it was given:
javascript
function addItem(arr, item) {
arr.push(item); // changes the original array
return arr;
}
const numbers = [1, 2, 3];
const result = addItem(numbers, 4);
console.log(numbers); // [1, 2, 3, 4], the source data changedThe immutable version builds a new array and leaves the input exactly as it was:
javascript
function addItem(arr, item) {
return [...arr, item]; // creates a new array
}
const numbers = [1, 2, 3];
const result = addItem(numbers, 4);
console.log(numbers); // [1, 2, 3], the source data is preserved
console.log(result); // [1, 2, 3, 4]The function did not change the input, it returned a new copy, and that is immutability.
Immutable and mutable operations
| Data type | Immutable way |
|---|---|
| Array | map(), filter(), concat(), spread ([...arr]) |
| Object | { ...obj, key: newValue } |
| String | Always immutable, a JavaScript string cannot be changed |
| Data type | Mutable operation |
| --- | --- |
| Array | push(), pop(), splice(), sort(), reverse() |
| Object | Direct assignment obj.key = value |
If a mutable operation is genuinely needed, copy first: [...arr].sort() instead of arr.sort().
Why immutability is worth it
- It keeps functions pure and predictable.
- It simplifies debugging and testing: the input is the same after the call as before it.
- It removes side effects, because nothing outside the function changes.
- It makes parallel work safe, there is no race over shared data.
- It makes state comparison and rollback easy, for example in React and Redux, where a new reference means "the data changed".
| Property | Immutable function |
|---|---|
| Changes the input data | No |
| Creates new structures | Yes |
| Side effects | No |
| Predictability | High |
| Examples | map, filter, reduce |
Common mistakes
- Calling
sort()orreverse()on a passed array: both change it in place. - Treating spread as a deep copy:
{ ...obj }copies only the top level, nested objects stay shared. - Mutating an argument and returning it, assuming nobody outside will notice: the caller holds the very same reference.
- Confusing
constwith immutability:constforbids reassigning the variable, it does not stop you changing the contents of an array or object. - Copying on every step inside a hot loop without measuring the cost: sometimes local mutation of the function's own copy is the right call.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.