Full Stack • Java • System Design • Cloud • AI Engineering

JavaScript2026-06-06

Pure Functions in JavaScript Explained

Learn Pure Functions in JavaScript including side effects, immutability, functional programming, testing benefits, real-world examples, and interview questions.

Pure Functions in JavaScript

Pure Functions are one of the fundamental concepts of Functional Programming.

Modern JavaScript frameworks and libraries heavily promote pure functions:

  • React
  • Redux
  • RxJS
  • Functional Programming Libraries
  • Serverless Functions

Understanding pure functions helps developers write:

  • Predictable Code
  • Testable Code
  • Reusable Code
  • Maintainable Code

What is a Pure Function?

A Pure Function is a function that follows two rules:

1. Same Input Always Produces Same Output

2. No Side Effects

If both conditions are satisfied:

The Function Is Pure

Simple Definition

Pure Function
=
Predictable Function

Why Do We Need Pure Functions?

Imagine:

function add(a, b) {
    return a + b;
}

Input:

add(10, 20);

Output:

30

Every time:

add(10, 20);

Output remains:

30

This predictability makes software easier to maintain.


Characteristics of Pure Functions

A Pure Function:

✅ Same Input → Same Output

✅ No Global Variable Dependency

✅ No External State Modification

✅ No Database Updates

✅ No API Calls

✅ No DOM Manipulation

✅ No Logging Side Effects


Pure Function Architecture

Input
  |
  v
Pure Function
  |
  v
Output

No external interaction occurs.


Example of a Pure Function

function multiply(a, b) {
    return a * b;
}

Input:

multiply(5, 2);

Output:

10

Every execution:

5 × 2 = 10

Always produces the same result.


Pure Function Flow

5, 2
 |
 v
multiply()
 |
 v
10

Predictable behavior.


Another Pure Function

function calculateTax(amount) {
    return amount * 0.18;
}

Input:

calculateTax(100);

Output:

18

Every time.


What is a Side Effect?

A Side Effect occurs when a function changes something outside itself.

Examples:

Modify Global Variables

Database Updates

API Calls

File Writes

DOM Updates

Console Logging

Changing Objects

Impure Function Example

let count = 0;

function increment() {

    count++;

    return count;

}

Output changes:

increment();
increment();
increment();

Result:

1
2
3

Not pure.


Why Is It Impure?

Because:

Depends On External State

Modifies External State

Impure Function Architecture

Global State
     |
     v
Function
     |
     v
Changes Global State

Example: Console Log Side Effect

function greet(name) {

    console.log(name);

}

This is considered:

Impure Function

Because:

Writes To External System

(console)


Example: DOM Manipulation

function updateTitle() {

    document.title =
    "CodeWithVenu";

}

Impure because:

Modifies Browser State

Example: API Call

function getUsers() {

    return fetch("/users");

}

Impure because:

Depends On External Service

Results may change.


Pure vs Impure Function

Pure

function square(num) {

    return num * num;

}

Impure

let multiplier = 2;

function square(num) {

    return num * multiplier;

}

Depends on external variable.


Pure Function Comparison

Feature Pure Function Impure Function
Same Input Same Output Yes Not Always
Side Effects No Yes
Easy Testing Yes Difficult
Predictable Yes No
Depends On External State No Yes

Pure Functions and Immutability

Pure functions should not modify input data.

Bad:

function addUser(users, user) {

    users.push(user);

    return users;

}

Impure.


Why?

Because:

Original Array Modified

Better Approach

function addUser(users, user) {

    return [...users, user];

}

Pure.


Memory Flow

Bad:

Array
 |
 v
Modified

Good:

Old Array
     |
     v
Create New Array

Real World Example

Order Calculation

function calculateTotal(
    price,
    tax
) {

    return price + tax;

}

Input:

calculateTotal(100, 20);

Output:

120

Always.


React and Pure Functions

React components are ideally pure.

Example:

function UserProfile({name}) {

    return <h1>{name}</h1>;

}

Input:

name="Venu"

Output:

<h1>Venu</h1>

Same input.

Same output.


Redux and Pure Functions

Reducers must be pure.

Good:

function reducer(
    state,
    action
) {

    return {
        ...state,
        count: state.count + 1
    };

}

Bad Redux Reducer

state.count++;

Mutates state.

Not pure.


Benefits of Pure Functions

Predictable

Same Input
=
Same Output

Easy Testing

expect(add(10,20))
.toBe(30);

No setup required.


Easy Debugging

No hidden dependencies.


Reusable

Works anywhere.


Parallel Processing

Safe because no shared state.


Functional Programming

Pure Functions are a core principle of:

Functional Programming

Other concepts:

Immutability

Higher Order Functions

Function Composition

Declarative Programming

Common Mistakes

Modifying Parameters

Bad:

function update(user) {

    user.name = "Venu";

}

Impure.


Using Global Variables

Bad:

let taxRate = 0.18;

function calculate(price) {

    return price * taxRate;

}

Depends on external state.


Random Values

function generateId() {

    return Math.random();

}

Impure.

Same input does not produce same output.


Current Time

function getTime() {

    return Date.now();

}

Impure.

Output changes every call.


Pure Version Example

Instead of:

function calculate() {

    return Date.now();

}

Use:

function calculate(time) {

    return time + 100;

}

Pass external data as parameters.


Real World Example

Bad:

let discount = 0.10;

function calculate(price) {

    return price - (price * discount);

}

Better

function calculate(
    price,
    discount
) {

    return price - (price * discount);

}

Pure.


Interview Questions

What is a Pure Function?

A function that:

Same Input → Same Output

No Side Effects

What is a Side Effect?

Any operation that affects external state.

Examples:

  • API Calls
  • DOM Updates
  • Logging
  • Global Variables

Why Are Pure Functions Important?

They are:

  • Predictable
  • Testable
  • Reusable

Is console.log a Side Effect?

Yes.


Is Math.random Pure?

No.

Output changes.


Is Date.now Pure?

No.

Output changes.


Are React Components Pure?

Ideally yes.


Why Are Redux Reducers Pure?

To maintain predictable state updates.


Cheat Sheet

Pure Function
-------------
Same Input
=
Same Output

No Side Effects

Examples
--------
add()
multiply()
calculateTax()

Impure Examples
---------------
console.log()
fetch()
Date.now()
Math.random()
DOM Updates

Benefits
--------
Predictable
Testable
Reusable
Maintainable

Functional Programming
----------------------
Pure Functions
Immutability
Higher Order Functions
Composition

Summary

Pure Functions are one of the most important principles in modern JavaScript development.

A Pure Function:

Same Input
=
Same Output

AND

No Side Effects

Benefits:

  • Easier Testing
  • Better Debugging
  • Predictable Behavior
  • Reusable Logic

Pure Functions are heavily used in:

  • React
  • Redux
  • Functional Programming
  • Modern JavaScript Applications

Mastering pure functions is essential before learning:

  • Function Composition
  • Currying
  • Redux
  • React Performance Optimization
  • Functional Programming Patterns

The best JavaScript developers strive to make most business logic pure whenever possible.


. Pass external dependencies as parameters

// ❌ IMPURE
let taxRate = 0.08;
function calculateTax(amount) {
    return amount * taxRate;
}

// ✅ PURE
function calculateTax(amount, taxRate) {
    return amount * taxRate;
}
  1. Return new values instead of mutating
// ❌ IMPURE
function addItem(array, item) {
    array.push(item);
    return array;
}

// ✅ PURE
function addItem(array, item) {
    return [...array, item];
}
  1. Separate side effects from logic
// ❌ IMPURE
function processOrder(order) {
    const total = calculateTotal(order);
    saveToDatabase(order);  // Side effect
    return total;
}

// ✅ PURE (logic) + Impure (effects)
function calculateOrderTotal(order) {
    return order.items.reduce((sum, item) => 
        sum + item.price, 0
    );
}

function processOrder(order) {
    const total = calculateOrderTotal(order);
    saveToDatabase({ ...order, total });
    return total;
}
  1. Accept time/random values as parameters
// ❌ IMPURE
function createTimestamp() {
    return Date.now();
}

// ✅ PURE
function formatTimestamp(timestamp) {
    return new Date(timestamp).toISOString();
}

// Usage
const timestamp = Date.now();  // Impure (isolated)
const formatted = formatTimestamp(timestamp);  // Pure

Q5: Explain the difference between pure and impure functions in Redux.

Answer:

Redux requires pure reducers for predictable state management:

// ❌ IMPURE REDUCER - Mutates state
function badReducer(state = { count: 0 }, action) {
    switch (action.type) {
        case 'INCREMENT':
            state.count++;  // Mutation!
            return state;
        default:
            return state;
    }
}

// ✅ PURE REDUCER - Returns new state
function goodReducer(state = { count: 0 }, action) {
    switch (action.type) {
        case 'INCREMENT':
            return {
                ...state,
                count: state.count + 1
            };
        default:
            return state;
    }
}

// Why pure reducers matter:
// 1. Time-travel debugging works
// 2. State changes are trackable
// 3. Performance optimization possible
// 4. Predictable state updates

Complex state updates:

// ✅ PURE - Nested state update
function userReducer(state = { users: [] }, action) {
    switch (action.type) {
        case 'UPDATE_USER':
            return {
                ...state,
                users: state.users.map(user =>
                    user.id === action.payload.id
                        ? { ...user, ...action.payload.updates }
                        : user
                )
            };
        
        case 'ADD_USER':
            return {
                ...state,
                users: [...state.users, action.payload]
            };
        
        case 'REMOVE_USER':
            return {
                ...state,
                users: state.users.filter(user => 
                    user.id !== action.payload
                )
            };
        
        default:
            return state;
    }
}

Q6: How do pure functions help with testing?

Answer:

Pure functions are extremely easy to test:

// Pure function
function calculateDiscount(price, discountPercent) {
    return price * (1 - discountPercent / 100);
}

// Simple test - no setup needed
describe('calculateDiscount', () => {
    test('applies 10% discount', () => {
        expect(calculateDiscount(100, 10)).toBe(90);
    });
    
    test('applies 20% discount', () => {
        expect(calculateDiscount(100, 20)).toBe(80);
    });
    
    test('handles zero discount', () => {
        expect(calculateDiscount(100, 0)).toBe(100);
    });
});

// Impure function
let globalTaxRate = 0.08;
function calculateTax(amount) {
    return amount * globalTaxRate;
}

// Complex test - requires setup
describe('calculateTax', () => {
    beforeEach(() => {
        globalTaxRate = 0.08;  // Reset global state
    });
    
    test('calculates tax', () => {
        expect(calculateTax(100)).toBe(8);
    });
    
    test('uses updated tax rate', () => {
        globalTaxRate = 0.10;
        expect(calculateTax(100)).toBe(10);
    });
});

Benefits for testing:

  • No mocking required
  • No setup/teardown needed
  • Tests are isolated
  • Easy to write property-based tests
  • Deterministic results

12. Cheat Sheet

┌─────────────────────────────────────────────────────┐
│           PURE FUNCTIONS CHEAT SHEET                │
├─────────────────────────────────────────────────────┤
│                                                     │
│  DEFINITION                                         │
│  ──────────                                         │
│  1. Same Input → Same Output (Deterministic)        │
│  2. No Side Effects                                 │
│                                                     │
│  CHARACTERISTICS                                    │
│  ───────────────                                    │
│  ✅ Predictable                                     │
│  ✅ Testable                                        │
│  ✅ Cacheable (Memoizable)                          │
│  ✅ Parallelizable                                  │
│  ✅ Referentially Transparent                       │
│                                                     │
│  SIDE EFFECTS TO AVOID                              │
│  ──────────────────────                             │
│  ❌ Modifying global variables                      │
│  ❌ Modifying parameters                            │
│  ❌ HTTP requests                                   │
│  ❌ Database operations                             │
│  ❌ File I/O                                        │
│  ❌ DOM manipulation                                │
│  ❌ Console logging                                 │
│  ❌ Math.random()                                   │
│  ❌ Date.now()                                      │
│                                                     │
│  PURE EXAMPLES                                      │
│  ──────────────                                     │
│  function add(a, b) {                               │
│      return a + b;                                  │
│  }                                                  │
│                                                     │
│  function multiply(a, b) {                          │
│      return a * b;                                  │
│  }                                                  │
│                                                     │
│  function addItem(arr, item) {                      │
│      return [...arr, item];                         │
│  }                                                  │
│                                                     │
│  function updateUser(user, updates) {               │
│      return { ...user, ...updates };                │
│  }                                                  │
│                                                     │
│  IMPURE EXAMPLES                                    │
│  ────────────────                                   │
│  let count = 0;                                     │
│  function increment() {                             │
│      count++;  // Modifies external state           │
│      return count;                                  │
│  }                                                  │
│                                                     │
│  function log(msg) {                                │
│      console.log(msg);  // Side effect              │
│  }                                                  │
│                                                     │
│  function fetchData() {                             │
│      return fetch('/api');  // Side effect          │
│  }                                                  │
│                                                     │
│  MAKING FUNCTIONS PURE                              │
│  ──────────────────────                             │
│  1. Pass dependencies as parameters                 │
│  2. Return new values (don't mutate)                │
│  3. Separate logic from side effects                │
│  4. Accept time/random as parameters                │
│                                                     │
│  IMMUTABILITY PATTERNS                              │
│  ──────────────────────                             │
│  // Arrays                                          │
│  [...arr, item]           // Add                    │
│  arr.filter(x => x !== y) // Remove                 │
│  arr.map(fn)              // Transform              │
│                                                     │
│  // Objects                                         │
│  { ...obj, key: value }   // Update                 │
│  { ...obj, ...updates }   // Merge                  │
│  const { key, ...rest } = obj  // Remove            │
│                                                     │
│  REACT USAGE                                        │
│  ────────────                                       │
│  // Pure component                                  │
│  function UserCard({ name, email }) {               │
│      return <div>{name}: {email}</div>;             │
│  }                                                  │
│                                                     │
│  // Memoization                                     │
│  const Memoized = React.memo(UserCard);             │
│                                                     │
│  REDUX USAGE                                        │
│  ────────────                                       │
│  function reducer(state, action) {                  │
│      switch (action.type) {                         │
│          case 'ADD':                                │
│              return {                               │
│                  ...state,                          │
│                  items: [...state.items, action.payload]│
│              };                                     │
│          default:                                   │
│              return state;                          │
│      }                                              │
│  }                                                  │
│                                                     │
│  TESTING                                            │
│  ───────                                            │
│  // Pure function - easy to test                    │
│  test('adds numbers', () => {                       │
│      expect(add(2, 3)).toBe(5);                     │
│  });                                                │
│                                                     │
│  // No setup, no mocking needed                     │
│                                                     │
│  PERFORMANCE                                        │
│  ───────────                                        │
│  // Memoization                                     │
│  const memoized = memoize(expensiveFn);             │
│                                                     │
│  // Lazy evaluation                                 │
│  function* lazyMap(arr, fn) {                       │
│      for (const item of arr) {                      │
│          yield fn(item);                            │
│      }                                              │
│  }                                                  │
│                                                     │
│  BENEFITS                                           │
│  ────────                                           │
│  • Easier to reason about                           │
│  • Simpler to test                                  │
│  • Better for debugging                             │
│  • Enables optimization                             │
│  • Safe for concurrency                             │
│  • Composable                                       │
│                                                     │
│  WHEN TO USE                                        │
│  ────────────                                       │
│  ✅ Business logic                                  │
│  ✅ Data transformations                            │
│  ✅ Calculations                                    │
│  ✅ Validation                                      │
│  ✅ Formatting                                      │
│  ✅ React components                                │
│  ✅ Redux reducers                                  │
│                                                     │
│  WHEN IMPURE IS OK                                  │
│  ──────────────────                                 │
│  • API calls (isolate in separate layer)            │
│  • Database operations                              │
│  • File I/O                                         │
│  • Logging (development)                            │
│  • Event handlers                                   │
│                                                     │
└─────────────────────────────────────────────────────┘

13. Summary

Pure functions are a cornerstone of modern JavaScript development and functional programming. They provide predictability, testability, and maintainability that make complex applications easier to build and maintain.

Key Takeaways

┌─────────────────────────────────────────────────────┐
│              PURE FUNCTIONS SUMMARY                 │
├─────────────────────────────────────────────────────┤
│                                                     │
│  TWO FUNDAMENTAL RULES                              │
│  ─────────────────────                              │
│  1. Deterministic Behavior                          │
│     Same Input → Same Output (Always)               │
│                                                     │
│  2. No Side Effects                                 │
│     No External State Changes                       │
│                                                     │
│  CORE BENEFITS                                      │
│  ─────────────                                      │
│  ✅ Predictable - Easy to reason about              │
│  ✅ Testable - Simple unit tests                    │
│  ✅ Debuggable - No hidden dependencies             │
│  ✅ Reusable - Works anywhere                       │
│  ✅ Optimizable - Memoization possible              │
│  ✅ Parallelizable - Thread-safe                    │
│                                                     │
│  REAL-WORLD APPLICATIONS                            │
│  ───────────────────────                            │
│  • React Components                                 │
│  • Redux Reducers                                   │
│  • Data Transformations                             │
│  • Business Logic                                   │
│  • Validation Functions                             │
│  • Utility Functions                                │
│                                                     │
│  BEST PRACTICES                                     │
│  ───────────────                                    │
│  1. Pass dependencies as parameters                 │
│  2. Return new values (immutability)                │
│  3. Separate pure logic from side effects           │
│  4. Use pure functions for business logic           │
│  5. Isolate impure operations                       │
│  6. Test pure functions extensively                 │
│                                                     │
└─────────────────────────────────────────────────────┘

Why Pure Functions Matter

  1. Code Quality: Pure functions lead to cleaner, more maintainable code
  2. Testing: Dramatically simplifies testing and debugging
  3. Performance: Enables powerful optimizations like memoization
  4. Concurrency: Safe for parallel execution
  5. Functional Programming: Foundation for advanced FP concepts

Modern JavaScript Ecosystem

Pure functions are essential in:

  • React: Components should be pure for optimal performance
  • Redux: Reducers must be pure for predictable state management
  • Functional Libraries: Lodash, Ramda, RxJS rely on pure functions
  • Testing: Jest, Mocha benefit from pure function simplicity
  • Build Tools: Tree-shaking and dead code elimination work better with pure functions

Next Steps

After mastering pure functions, explore:

  1. Function Composition: Combining pure functions
  2. Currying: Partial application of functions
  3. Immutability: Deep immutability patterns
  4. Functional Programming: Advanced FP concepts
  5. Performance: Memoization and optimization techniques

Final Thoughts

// Strive for purity in your functions
// Your future self will thank you

// ✅ Pure, predictable, testable
function calculateTotal(items, taxRate) {
    const subtotal = items.reduce((sum, item) => 
        sum + item.price, 0
    );
    return subtotal * (1 + taxRate);
}

// This simple function is:
// • Easy to understand
// • Easy to test
// • Easy to reuse
// • Easy to optimize
// • Easy to maintain

// That's the power of pure functions!

Pure functions are not just a programming technique—they're a mindset that leads to better software design. By embracing pure functions, you write code that is more reliable, maintainable, and enjoyable to work with.


Related Topics:

Practice Resources:

  • Write pure versions of common array methods
  • Refactor impure code to pure functions
  • Build a Redux reducer with pure functions
  • Create a memoization utility
  • Implement functional data transformations

Master pure functions to write better JavaScript code! 🚀