Functional programming (FP) treats computation as the evaluation of functions and emphasizes avoiding mutable state and side effects.

Core Principles

1. Pure Functions

Same input always produces same output; no side effects:

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

// Impure — depends on external state
let counter = 0;
function increment() {
    return ++counter;
}

// Impure — modifies input
function appendItem(arr, item) {
    arr.push(item);
    return arr;
}
  

2. Immutability

Create new values instead of mutating existing ones:

  // Mutable
let user = { name: 'Alice', age: 25 };
user.age = 26;

// Immutable update
let updatedUser = { ...user, age: 26 };
let newTags = [...user.tags, 'vip']; // if tags existed
  

3. First-Class Functions

Functions are values — assign, pass, return them:

  const operations = {
    add: (a, b) => a + b,
    multiply: (a, b) => a * b
};
  

map, filter, reduce

The foundation of functional array processing:

  let numbers = [1, 2, 3, 4, 5];

let doubled = numbers.map(n => n * 2);
let evens = numbers.filter(n => n % 2 === 0);
let sum = numbers.reduce((acc, n) => acc + n, 0);

// Chain
let result = numbers
    .filter(n => n % 2 === 0)
    .map(n => n * 2)
    .reduce((acc, n) => acc + n, 0);
console.log(result); // 12 (2*2 + 4*2)
  

Declarative vs Imperative

  // Imperative
let total = 0;
for (let i = 0; i < numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        total += numbers[i] * 2;
    }
}

// Declarative
let total2 = numbers
    .filter(n => n % 2 === 0)
    .map(n => n * 2)
    .reduce((a, b) => a + b, 0);
  

Avoiding Side Effects

  // Side effect: modifies external state
let log = [];
function process(data) {
    log.push(data); // side effect
    return data.toUpperCase();
}

// No side effect: return new data, log separately
function processPure(data) {
    return data.toUpperCase();
}
  

Recursion

Functional style often uses recursion instead of loops:

  function sumArray(arr) {
    if (arr.length === 0) return 0;
    return arr[0] + sumArray(arr.slice(1));
}

function factorial(n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
  

Maybe / Optional Pattern (Manual)

Handle null/undefined without exceptions:

  const Maybe = {
    of(value) {
        return {
            isNothing: value == null,
            value,
            map(fn) {
                return this.isNothing ? this : Maybe.of(fn(this.value));
            },
            getOr(defaultVal) {
                return this.isNothing ? defaultVal : this.value;
            }
        };
    }
};

Maybe.of(null).map(x => x * 2).getOr(0); // 0
Maybe.of(5).map(x => x * 2).getOr(0);     // 10
  

When to Use FP

  • Data transformation pipelines
  • React state updates (immutability)
  • Testing (pure functions are easy to test)
  • Concurrent code (no shared mutable state)

Functional techniques complement OOP — JavaScript supports both styles effectively.