Functional Programming in JavaScript: From Theory to Practice
Functional Programming (FP) is a paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. In modern JavaScript, especially in the Node.js environment, the functional approach is becoming increasingly popular due to its predictability, testability, and modularity. In this article, we will break down the key concepts of FP and show how to apply them in real-world projects.
1. Pure Functions and No Side Effects
A pure function is a function that:
- Always returns the same result for the same arguments (determinism).
- Does not cause side effects (does not modify external variables, does not output data, does not access the file system).
Example of a pure function:
// Pure function: adds two numbersconst add = (a, b) => a + b;
console.log(add(2, 3)); // 5console.log(add(2, 3)); // 5 — always the sameExample of an impure function:
let counter = 0;const increment = () => { counter++; // Side effect: modifies an external variable return counter;};
console.log(increment()); // 1console.log(increment()); // 2 — different resultIn functional programming, we strive to write only pure functions. This makes the code easier to test and debug.
2. Data Immutability
Immutability means that data is not changed after creation. Instead of modifying an existing object, we create a new copy of it with the necessary changes. In JavaScript, the spread operator (...) or Object.assign methods are often used for this.
Example of immutable object update:
const user = { name: 'Alice', age: 30 };
// Bad: mutationuser.age = 31;
// Good: create a new objectconst updatedUser = { ...user, age: 31 };
console.log(user); // { name: 'Alice', age: 30 }console.log(updatedUser); // { name: 'Alice', age: 31 }For arrays, we also use immutable methods:
const numbers = [1, 2, 3];
// Mutation (bad)numbers.push(4);
// Immutable (good)const newNumbers = [...numbers, 4];
console.log(numbers); // [1, 2, 3]console.log(newNumbers); // [1, 2, 3, 4]3. Higher-Order Functions: map, filter, reduce
Higher-order functions are functions that take other functions as arguments or return them. The three most popular methods in JavaScript are map, filter, and reduce. They allow processing arrays without loops and mutations.
3.1. map() — Transforming an Array
The map method creates a new array by applying a function to each element of the original array.
const prices = [100, 200, 300];const withTax = prices.map(price => price * 1.2);
console.log(withTax); // [120, 240, 360]// The original array has not changedconsole.log(prices); // [100, 200, 300]3.2. filter() — Filtering an Array
The filter method returns a new array containing only the elements for which the passed function returned true.
const ages = [15, 22, 18, 30, 12];const adults = ages.filter(age => age >= 18);
console.log(adults); // [22, 18, 30]3.3. reduce() — Data Aggregation
The reduce method reduces an array to a single value (number, object, string).
const numbers = [1, 2, 3, 4, 5];const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15By combining these methods, you can solve complex problems in a functional style:
const users = [