Functional Programming in JavaScript: Basics and Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction to Functional Programming in JavaScript



Functional Programming (FP) is a programming paradigm where computation is treated as the application of mathematical functions. Unlike the imperative approach, where we write a sequence of instructions that change the program's state, the functional style focuses on what needs to be computed, rather than how to do it.



JavaScript, being a multi-paradigm language, is well-suited for functional programming. In the Node.js environment, this approach is especially useful for data processing, working with streams, and building reliable server-side applications. In this article, we will break down the key concepts of FP using practical examples.



Core Principles of Functional Programming



Pure Functions

A pure function is a function that:

  • Always returns the same result for the same arguments (determinism).
  • Has no side effects (does not modify external variables, does not output to the console, does not write to files).


// Pure functionconst add = (a, b) => a + b;

// Impure function (side effect — console output)const impureAdd = (a, b) => { console.log(`Adding ${a} and ${b}`); return a + b;};

// Impure function (depends on external state)let counter = 0;const increment = () => ++counter;


Advantages of pure functions: they are easy to test, debug, and parallelize. They are predictable and do not depend on the execution context.



Immutability

Immutability means that data, once created, cannot be changed. Instead of modifying an existing object, we create a new copy of it with the desired changes.



// Mutable approach (bad)const user = { name: 'Ivan', age: 30 };user.age = 31; // Directly modifying

// Immutable approach (good)const user2 = { name: 'Maria', age: 25 };const updatedUser = { ...user2, age: 26 };// The original user2 object remains unchanged

// Working with arraysconst numbers = [1, 2, 3];const newNumbers = [...numbers, 4]; // [1, 2, 3, 4]// numbers remains [1, 2, 3]


In Node.js, immutability is especially important when working with requests and application state to avoid unexpected mutations in asynchronous code.



Higher-Order Functions and Closures



Higher-Order Functions

These are functions that take other functions as arguments or return them. The built-in array methods map, filter, and reduce are classic examples.



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

// map — transforms each elementconst doubled = numbers.map(n => n * 2);// [2, 4, 6, 8, 10]

// filter — keeps elements based on a conditionconst evens = numbers.filter(n => n % 2 === 0);// [2, 4]

// reduce — reduces the array to a single valueconst sum = numbers.reduce((acc, n) => acc + n, 0);// 15


Closures

A closure is a function that "remembers" the variables from the scope in which it was created, even after that scope has finished executing.



const createCounter = () => {    let count = 0; // Private variable    return () => ++count;};

const counter1 = createCounter();console.log(counter1()); // 1console.log(counter1()); // 2

const counter2 = createCounter();console.log(counter2()); // 1 (independent counter)


Closures are widely used for creating function factories and encapsulating state in a functional style.



Currying and Function Composition



Currying

Currying is the transformation of a function that takes multiple arguments into a sequence of functions, each of which

Blogs

Book Recommendations