ReviseAlgo Logo

Functional Programming

FP Principles — Immutability, Purity, Referential Transparency

Master the foundational principles of Functional Programming in JavaScript. Learn purity, immutability, side effects, and referential transparency.

Last Updated: July 15, 2026 10 min read

1. Introduction

Functional Programming (FP) is a programming paradigm that treats computation as the evaluation of mathematical functions, avoiding mutable state and side effects. Its core principles are Purity, Immutability, and Referential Transparency.

2. Why It Matters

Shared mutable state makes applications difficult to debug. Multiple parts of an app mutating the same global object can result in race conditions. FP prevents these issues, making code predictable, testable, and easier to parallelize.

3. Real-World Analogy

Think of a Vending Machine:

  • Stateful OOP (Manual Store Counter): You ask a clerk for a drink. The clerk goes to the shelf, counts the items, modifies a ledger, updates a register, and hands you the drink. If the clerk miscounts or mutates the register incorrectly, the store state is corrupted.
  • Pure Function (Vending Machine): You input a code (arguments) and money. The machine processes the input and drops the drink. Given the same code and coins, it always drops the same drink (determinism) and doesn't change the layout of other shelves or call external systems (no side effects). It is referentially transparent: if the price is $2, you can swap the transaction for $2 directly.

4. Core Principles

Let's explore the three core principles of Functional Programming:

1. Pure Functions:

A function is pure if:
• Given the same inputs, it always returns the same output (determinism).
• It has no side effects (e.g. it does not modify external variables, log to consoles, write to disk, or perform network requests).

2. Immutability:

Data cannot be modified after it is created. Instead of mutating objects, create new ones with the updated properties.

3. Referential Transparency:

An expression is referentially transparent if it can be replaced with its evaluated value without changing the application's behavior.

5. Practical Example

This script demonstrates sorting an array immutably by creating a copy first, preventing mutations to the original collection:

6. Common Mistakes

  • Assuming array methods like push or splice are pure: Methods like push(), pop(), shift(), unshift(), and splice() mutate the array in-place. Use non-mutating equivalents like concat(), slice(), or the spread operator instead.

7. Quick Quiz

Q1: Which of the following describes a function that is pure?

A) It updates a local database record asynchronously

B) Given the same inputs, it always returns the same output and causes no side effects

Answer: B — Pure functions are deterministic and do not cause side effects, ensuring predictable execution.

8. Scenario-Based Challenge

The Shopping Cart Item Adder:

An application tracks shopping cart states: const cart = [{ id: 1, qty: 1 }]. You want to write a function addItem(cart, item) that appends an item to the cart (or increments its quantity if it already exists) without mutating the original cart array or item objects. Write this pure function.

9. Debugging Exercise

Explain why this filter helper function is impure, and how to make it pure:

const usersList = [
  { name: 'Alice', active: true },
  { name: 'Bob', active: false }
];

// Objective: filter active users function filterActive() { // Bug: references global variable directly inside! return usersList.filter(u => u.active); }

View Solution

Diagnosis: The function depends on the global variable usersList. If another script mutates usersList, calling filterActive() with the same arguments will return different results, making the function impure.

Fix: Pass the list of users as an argument to make the function pure and self-contained:

function filterActive(list) {
  return list.filter(u => u.active); // Pure!
}

10. Interview Questions

🟢 Q1: Define side effects and explain why they make code difficult to test.

Answer: A side effect is any change that a function makes to state outside its local scope (such as modifying global variables, writing to consoles, saving database records, or making network requests).
Side effects make code difficult to test because:
Mocking Dependencies: Tests must set up and mock the external systems (like databases or APIs) that the function interacts with.
Test Pollution: Tests can contaminate each other if they mutate the same global variables or test database records, requiring tear-down and setup steps.

11. Production Considerations

  • Isolate Side Effects: While side effects are necessary to interact with databases and APIs, keep your application's core logic pure. Isolate side effects inside designated boundaries (such as event handlers or middleware layers), keeping your business logic predictable and easy to test.