Javascript 19 🧬 pure functions
A pure function is a function that adheres to two primary principles: it always produces the same output for the same input, and it has no side effects — meaning it doesn’t modify any external state.
A Quick Look at the Examples
// 1. Simple mathematical operation — pure
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
// 2. Array transformation — pure (doesn't modify original)
const numbers = [1, 2, 3, 4];
const doubledNumbers = numbers.map(n => n * 2);
console.log(numbers); // [1, 2, 3, 4] — unchanged!
console.log(doubledNumbers); // [2, 4, 6, 8]
// 3. Factory function — pure (creates new object)
function createPerson(name, age) {
return { name, age };
}
const person1 = createPerson("Alice", 30);
console.log(person1); // { name: "Alice", age: 30 }
// 4. Filter — pure (doesn't modify original)
const evenNumbers = numbers.filter(n => n % 2 === 0);
console.log(evenNumbers); // [2, 4]
a. What is a Pure Function?
A pure function is a function that adheres to two primary principles:
1. Determinism
Given the same input, a pure function will always produce the same output.
// ✅ Pure — same input, same output
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
console.log(add(2, 3)); // 5 (always)
// ❌ Impure — different output for same input
function randomAdd(a, b) {
return a + b + Math.random(); // Different every time!
}
2. No Side Effects
A pure function does not modify any external state or variables.
// ✅ Pure — no side effects
function add(a, b) {
return a + b;
}
// ❌ Impure — modifies external state
let total = 0;
function addToTotal(n) {
total += n; // Side effect!
return total;
}
Characteristics of Pure Functions
| Characteristic | Description |
|---|---|
| Immutability | They do not change the input data — they work on a copy or produce new data |
| Predictability | Since they have no side effects, their behavior is entirely predictable based solely on their inputs |
| Testability | Because they’re independent of external state and always return the same result for given inputs, they are easier to test |
What Are Side Effects?
A side effect is any observable change to the state outside the function’s scope.
| Side Effect | Example |
|---|---|
| Modifying global variables | total += n; |
| Mutating input parameters | arr.push(item); |
| Logging to console | console.log(...) |
| Writing to files/databases | fs.writeFile(...) |
| Making network requests | fetch(...) |
| Changing the DOM | element.textContent = ... |
Math.random(), Date.now() | Non-deterministic |
b. Pure Function Examples and Benefits
Example 1: Simple Mathematical Operation
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
Why it’s pure:
- ✅ Same input → same output
- ✅ No side effects
- ✅ Doesn’t modify
aorb
Example 2: Transforms an Array Without Modifying the Original
const numbers = [1, 2, 3, 4];
const doubledNumbers = numbers.map(n => n * 2);
console.log(numbers); // [1, 2, 3, 4] — unchanged!
console.log(doubledNumbers); // [2, 4, 6, 8]
Why it’s pure:
- ✅
map()creates a new array — doesn’t modify the original - ✅ Same input → same output
- ✅ Original array is untouched
Compare with the impure version:
// ❌ Impure — mutates the original array
function doubleInPlace(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] *= 2; // Side effect!
}
return arr;
}
const numbers = [1, 2, 3, 4];
const doubled = doubleInPlace(numbers);
console.log(numbers); // [2, 4, 6, 8] — MODIFIED!
Example 3: Generates a New Object Without Modifying the Input
function createPerson(name, age) {
return { name, age };
}
const person1 = createPerson("Alice", 30);
console.log(person1); // { name: "Alice", age: 30 }
Why it’s pure:
- ✅ Creates a new object each time
- ✅ Same input → same output
- ✅ Doesn’t modify external state
Example 4: Filters an Array
const evenNumbers = numbers.filter(n => n % 2 === 0);
console.log(evenNumbers); // [2, 4]
Why it’s pure:
- ✅
filter()creates a new array - ✅ Original array is untouched
- ✅ Same input → same output
Benefits of Using Pure Functions
| Benefit | Description |
|---|---|
| Predictability | Easier to reason about and understand because they always produce the same output for given inputs |
| Testability | Can be tested independently without setting up complex environments or mocking dependencies |
| Concurrency | Safe to use in concurrent contexts since they don’t depend on external state |
| Reusability | Self-contained, so pure functions can be easily reused across different parts of an application |
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pure Functions</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
color: #333;
line-height: 1.6;
}
h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
.demo-box {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 15px 0;
}
pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
}
.keyword { color: #569cd6; }
.string { color: #ce9178; }
.number { color: #b5cea8; }
.function { color: #dcdcaa; }
.comment { color: #6a9955; }
.boolean { color: #569cd6; }
.error { color: #f48771; }
.success { color: #4ec9b0; }
#output {
background: #e9ecef;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
min-height: 40px;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
border-left: 4px solid #007bff;
white-space: pre-wrap;
}
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th { background: #007bff; color: white; }
tr:nth-child(even) { background: #f8f9fa; }
.btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
margin: 5px;
transition: all 0.3s;
}
.btn:hover {
background: #0056b3;
transform: translateY(-2px);
}
.btn-success { background: #28a745; }
.btn-success:hover { background: #1e7e34; }
.btn-danger { background: #dc3545; }
.btn-danger:hover { background: #a71d2a; }
.comparison {
display: flex;
gap: 20px;
flex-wrap: wrap;
margin: 15px 0;
}
.comparison > div {
flex: 1;
min-width: 250px;
padding: 15px;
border-radius: 8px;
}
.pure-box {
background: #d4edda;
border-left: 4px solid #28a745;
}
.impure-box {
background: #f8d7da;
border-left: 4px solid #dc3545;
}
</style>
</head>
<body>
<h1>Pure Functions</h1>
<div class="demo-box">
<h2>1. What is a Pure Function?</h2>
<pre>
<span class="comment">// ✅ Pure — same input, same output, no side effects</span>
<span class="keyword">function</span> <span class="function">add</span>(a, b) {
<span class="keyword">return</span> a + b;
}
<span class="comment">// ❌ Impure — modifies external state</span>
<span class="keyword">let</span> total = <span class="number">0</span>;
<span class="keyword">function</span> <span class="function">addToTotal</span>(n) {
total += n; <span class="comment">// Side effect!</span>
<span class="keyword">return</span> total;
}
</pre>
</div>
<div class="demo-box">
<h2>2. Pure vs Impure — Side by Side</h2>
<div class="comparison">
<div class="pure-box">
<h3>✅ Pure Function</h3>
<pre style="background: #fff; color: #333; font-size: 0.85rem;">
<span class="keyword">function</span> <span class="function">double</span>(arr) {
<span class="keyword">return</span> arr.map(n => n * <span class="number">2</span>);
}
<span class="keyword">const</span> original = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="keyword">const</span> doubled = <span class="function">double</span>(original);
<span class="comment">// original: [1, 2, 3] ✅</span>
<span class="comment">// doubled: [2, 4, 6] ✅</span>
</pre>
<p><strong>Original array is unchanged!</strong></p>
</div>
<div class="impure-box">
<h3>❌ Impure Function</h3>
<pre style="background: #fff; color: #333; font-size: 0.85rem;">
<span class="keyword">function</span> <span class="function">doubleInPlace</span>(arr) {
<span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < arr.length; i++) {
arr[i] *= <span class="number">2</span>; <span class="comment">// Mutates!</span>
}
<span class="keyword">return</span> arr;
}
<span class="keyword">const</span> original = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="keyword">const</span> doubled = <span class="function">doubleInPlace</span>(original);
<span class="comment">// original: [2, 4, 6] ❌ MODIFIED!</span>
</pre>
<p><strong>Original array is destroyed!</strong></p>
</div>
</div>
</div>
<div class="demo-box">
<h2>3. Pure Functions in Array Methods</h2>
<pre>
<span class="keyword">const</span> numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>];
<span class="comment">// ✅ map — returns new array</span>
<span class="keyword">const</span> doubled = numbers.<span class="function">map</span>(n => n * <span class="number">2</span>);
<span class="comment">// ✅ filter — returns new array</span>
<span class="keyword">const</span> evens = numbers.<span class="function">filter</span>(n => n % <span class="number">2</span> === <span class="number">0</span>);
<span class="comment">// ✅ reduce — returns single value</span>
<span class="keyword">const</span> sum = numbers.<span class="function">reduce</span>((total, n) => total + n, <span class="number">0</span>);
console.log(numbers); <span class="comment">// [1, 2, 3, 4] — unchanged!</span>
console.log(doubled); <span class="comment">// [2, 4, 6, 8]</span>
console.log(evens); <span class="comment">// [2, 4]</span>
console.log(sum); <span class="comment">// 10</span>
</pre>
</div>
<div class="demo-box">
<h2>4. Interactive: Pure Function Playground</h2>
<div style="margin: 10px 0;">
<label style="font-weight: bold;">Array:</label>
<input type="text" id="arrayInput" value="1, 2, 3, 4, 5" style="padding: 8px; width: 200px; border: 2px solid #ddd; border-radius: 6px;">
</div>
<button class="btn btn-success" onclick="runPure('double')">Double (pure)</button>
<button class="btn btn-success" onclick="runPure('filterEven')">Filter Evens (pure)</button>
<button class="btn btn-success" onclick="runPure('sum')">Sum (pure)</button>
<button class="btn btn-danger" onclick="runImpure()">Double In Place (impure)</button>
<button class="btn" onclick="resetArray()">Reset</button>
<div id="interactiveOutput"></div>
</div>
<div class="demo-box">
<h2>5. Pure Function Benefits</h2>
<table>
<tr>
<th>Benefit</th>
<th>Description</th>
</tr>
<tr>
<td><strong>Predictability</strong></td>
<td>Same input always produces same output — easy to reason about</td>
</tr>
<tr>
<td><strong>Testability</strong></td>
<td>Test independently — no complex setup or mocking needed</td>
</tr>
<tr>
<td><strong>Concurrency</strong></td>
<td>Safe in concurrent contexts — no shared state</td>
</tr>
<tr>
<td><strong>Reusability</strong></td>
<td>Self-contained — easy to reuse across the app</td>
</tr>
<tr>
<td><strong>Cacheable</strong></td>
<td>Results can be memoized (same input = same output)</td>
</tr>
</table>
</div>
<div class="demo-box">
<h2>6. Live Output — Pure vs Impure</h2>
<div id="output">Loading...</div>
</div>
<script>
// ============================================
// Pure Functions — Live Demo
// ============================================
let results = [];
// ============================================
// ✅ PURE FUNCTIONS
// ============================================
results.push('📌 Pure Functions:\n');
// Pure: mathematical operation
function add(a, b) {
return a + b;
}
results.push(' add(2, 3) → ' + add(2, 3));
results.push(' add(2, 3) → ' + add(2, 3) + ' (always the same!)');
results.push('');
// Pure: map (doesn't modify original)
const originalNumbers = [1, 2, 3, 4];
const doubled = originalNumbers.map(n => n * 2);
results.push(' const numbers = [1, 2, 3, 4];');
results.push(' numbers.map(n => n * 2) → [' + doubled.join(', ') + ']');
results.push(' numbers (unchanged) → [' + originalNumbers.join(', ') + ']');
results.push('');
// Pure: filter (doesn't modify original)
const evens = originalNumbers.filter(n => n % 2 === 0);
results.push(' numbers.filter(n => n % 2 === 0) → [' + evens.join(', ') + ']');
results.push(' numbers (unchanged) → [' + originalNumbers.join(', ') + ']');
results.push('');
// Pure: reduce
const sum = originalNumbers.reduce((total, n) => total + n, 0);
results.push(' numbers.reduce((total, n) => total + n, 0) → ' + sum);
results.push(' numbers (unchanged) → [' + originalNumbers.join(', ') + ']');
results.push('');
// Pure: factory function
function createPerson(name, age) {
return { name, age };
}
const person1 = createPerson("Alice", 30);
results.push(' createPerson("Alice", 30) → ' + JSON.stringify(person1));
results.push('');
// ============================================
// ❌ IMPURE FUNCTIONS
// ============================================
results.push('📌 Impure Functions (for comparison):\n');
// Impure: modifies external state
let globalTotal = 0;
function addToGlobal(n) {
globalTotal += n; // Side effect!
return globalTotal;
}
results.push(' let globalTotal = 0;');
results.push(' addToGlobal(5) → ' + addToGlobal(5));
results.push(' addToGlobal(3) → ' + addToGlobal(3) + ' (depends on previous calls!)');
results.push(' globalTotal is now → ' + globalTotal);
results.push('');
// Impure: mutates input
function doubleInPlace(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] *= 2;
}
return arr;
}
const mutableArray = [1, 2, 3];
results.push(' const arr = [1, 2, 3];');
results.push(' doubleInPlace(arr) → [' + doubleInPlace([...mutableArray]).join(', ') + ']');
results.push(' arr (MODIFIED!) → [' + mutableArray.join(', ') + ']');
results.push(' ⚠️ Original array was mutated!');
results.push('');
// Impure: non-deterministic
function randomAdd(a, b) {
return a + b + Math.floor(Math.random() * 10);
}
results.push(' randomAdd(2, 3) → ' + randomAdd(2, 3));
results.push(' randomAdd(2, 3) → ' + randomAdd(2, 3) + ' (different every time!)');
results.push('');
// ============================================
// Comparison Summary
// ============================================
results.push('📌 Summary:\n');
results.push(' ✅ Pure: Same input → Same output, no side effects');
results.push(' ❌ Impure: Modifies state, depends on context, non-deterministic');
document.getElementById('output').textContent = results.join('\n');
// ============================================
// Interactive Functions
// ============================================
// ✅ Pure functions
const pureFunctions = {
double: (arr) => arr.map(n => n * 2),
filterEven: (arr) => arr.filter(n => n % 2 === 0),
sum: (arr) => arr.reduce((total, n) => total + n, 0)
};
// Keep track of the current array
let currentArray = [1, 2, 3, 4, 5];
function getArray() {
const input = document.getElementById('arrayInput').value;
return input.split(',').map(n => Number(n.trim())).filter(n => !isNaN(n));
}
function runPure(operation) {
const arr = getArray();
const output = document.getElementById('interactiveOutput');
const original = [...arr]; // Snapshot
const result = pureFunctions[operation](arr);
let resultDisplay = Array.isArray(result) ? '[' + result.join(', ') + ']' : result;
output.innerHTML = `
<p><strong>✅ Pure Function: ${operation}</strong></p>
<p>Input: <code>[${original.join(', ')}]</code></p>
<p>Output: <code style="color: #28a745;">${resultDisplay}</code></p>
<p style="color: #28a745;">Original array is unchanged: <code>[${arr.join(', ')}]</code></p>
`;
}
function runImpure() {
const arr = getArray();
const output = document.getElementById('interactiveOutput');
const original = [...arr]; // Snapshot before
// Impure — mutates the array
for (let i = 0; i < arr.length; i++) {
arr[i] *= 2;
}
output.innerHTML = `
<p><strong>❌ Impure Function: doubleInPlace</strong></p>
<p>Before: <code>[${original.join(', ')}]</code></p>
<p>After: <code style="color: #dc3545;">[${arr.join(', ')}]</code></p>
<p style="color: #dc3545;">⚠️ The original array was MODIFIED!</p>
`;
// Update the input to reflect the mutation
document.getElementById('arrayInput').value = arr.join(', ');
}
function resetArray() {
document.getElementById('arrayInput').value = '1, 2, 3, 4, 5';
document.getElementById('interactiveOutput').innerHTML = '';
}
</script>
</body>
</html>
Quick Reference
Pure Function Checklist
| Question | Pure? |
|---|---|
| Same input → same output? | ✅ Must be YES |
| Modifies external state? | ❌ Must be NO |
| Modifies input parameters? | ❌ Must be NO |
| Depends on external state? | ❌ Must be NO |
Uses Math.random() or Date.now()? | ❌ Must be NO |
| Logs to console? | ⚠️ Technically a side effect |
Pure vs Impure
| Aspect | Pure | Impure |
|---|---|---|
| Same input → same output | ✅ Yes | ❌ Not guaranteed |
| Side effects | ✅ None | ❌ May have |
| Mutates inputs | ✅ No | ❌ May mutate |
| Testability | ✅ Easy | ❌ Hard |
| Predictability | ✅ High | ❌ Low |
| Cacheable | ✅ Yes | ❌ No |
Common Side Effects
| Side Effect | Example |
|---|---|
| Modifying globals | total += n; |
| Mutating inputs | arr.push(x); |
| Console output | console.log(...) |
| DOM changes | el.textContent = ... |
| Network requests | fetch(...) |
| File I/O | fs.writeFile(...) |
| Random values | Math.random() |
| Current time | Date.now() |
Best Practices
✅ Do This:
// Pure: returns new array
function double(arr) {
return arr.map(n => n * 2);
}
// Pure: returns new object
function updateUser(user, newName) {
return { ...user, name: newName };
}
// Pure: doesn't modify inputs
function addItem(arr, item) {
return [...arr, item];
}
// Pure: deterministic
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Separate pure logic from side effects
function calculateTax(amount) { // Pure
return amount * 0.08;
}
function displayTotal(amount) { // Impure (DOM side effect)
document.getElementById('total').textContent = calculateTax(amount);
}
❌ Don’t Do This:
// Impure: mutates input
function addItem(arr, item) {
arr.push(item); // ❌ Side effect!
return arr;
}
// Impure: modifies global state
let count = 0;
function increment() {
count++; // ❌ Side effect!
}
// Impure: non-deterministic
function getId() {
return Math.random(); // ❌ Different every time!
}
// Impure: modifies object directly
function updateUser(user, name) {
user.name = name; // ❌ Mutates input!
return user;
}
// Impure: depends on external state
let taxRate = 0.08;
function calculateTax(amount) {
return amount * taxRate; // ❌ Depends on external variable!
}
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Mutating arrays | Original data corrupted | Use map, filter, spread |
| Mutating objects | Shared references affected | Use spread { ...obj } |
Using push/pop | Modifies original | Use concat or spread |
| Global state | Hard to test, unpredictable | Pass as parameter |
Math.random() | Non-deterministic | Pass random value as parameter |
Pure vs Impure — Visual
┌─────────────────────────────────────┐
│ PURE FUNCTION │
│ │
│ Input ────→ [Function] ────→ Output│
│ │
│ • No side effects │
│ • Same input = same output │
│ • Doesn't touch anything outside │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ IMPURE FUNCTION │
│ │
│ ┌──────────────┐ │
│ Input ────→ │ [Function] │ ────→ Output
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Global State │ │
│ │ DOM / Files │ │
│ │ Network / DB │ │
│ └──────────────┘ │
│ │
│ • Side effects │
│ • Same input ≠ same output │
└─────────────────────────────────────┘
Functional Programming Connection
Pure functions are the foundation of functional programming:
| Concept | Description |
|---|---|
| Pure Functions | Building blocks — no side effects |
| Immutability | Never modify data — create new copies |
| Higher-Order Functions | Functions that take/return functions |
| Composition | Combine pure functions into pipelines |
| Memoization | Cache results (only works with pure functions) |
// Functional pipeline with pure functions
const result = [1, 2, 3, 4, 5]
.filter(n => n % 2 === 0) // Pure
.map(n => n * 10) // Pure
.reduce((sum, n) => sum + n, 0); // Pure
console.log(result); // 60
Pro Tip: Pure functions are the building blocks of reliable software. They’re predictable (same input → same output), testable (no setup needed), cacheable (memoization works), and safe in concurrent environments. Aim to make as much of your code pure as possible, and isolate impure operations (DOM, network, files) to the edges of your application. Remember: map, filter, and reduce are pure — they return new arrays without modifying the original. But push, pop, sort, and splice mutate the array — avoid them in favor of pure alternatives!
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!