Key Concepts of Functional Programming in JavaScript
This article explains core functional programming concepts in JavaScript—including pure functions, side effects, currying, composition, and pointfree style—detailing their definitions, advantages, practical code examples, and how they improve code clarity, testability, and reusability.
Some Necessary Concepts
Pure Function : A function that, given the same input, always returns the same output and has no observable side effects.
Pure functions are the mathematical functions that form the basis of functional programming.
Side Effects : Any interaction with the external environment or change of system state during computation, such as modifying the file system, writing to a database, sending HTTP requests, changing state, logging, DOM queries, or accessing system state.
In short, any function that interacts with the outside world has side effects.
Currying
Currying transforms a function that takes multiple arguments into a sequence of functions each taking a single argument.
const add = x => y => x + y;
const increment = add(1);
const addTen = add(10);
increment(2); // 3
addTen(2); // 12Advantages of Functional Programming
Determinism: identical inputs always produce identical outputs.
Mathematical laws (associativity, commutativity, identity, distributivity) can be applied.
// associative
add(add(x, y), z) === add(x, add(y, z));
// commutative
add(x, y) === add(y, x);
// identity
add(x, 0) === x;
// distributive
multiply(x, add(y, z)) === add(multiply(x, y), multiply(x, z));Applicable Scenarios for Functional Programming
Mutable state
Unrestricted side effects
Unprincipled design
Functions as First-Class Citizens
In JavaScript, functions can be stored in arrays, passed as arguments, assigned to variables, etc., which enables reduction of unnecessary refactoring, increased reusability, and avoidance of this when properly adapted.
// example without this
httpGet('/post/2', renderPost);Value of Pure Functions
Cacheable
const memoize = f => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
cache[key] = cache[key] || f(...args);
return cache[key];
};
};
const squareNumber = memoize(x => x * x);
squareNumber(4); // 16
squareNumber(4); // 16 (cached)Portable / Self‑documenting
// impure version
const signUp = attrs => {
const user = saveUser(attrs);
welcomeUser(user);
};
// pure version
const signUp = (Db, Email, attrs) => () => {
const user = saveUser(Db, attrs);
welcomeUser(Email, user);
};Pure functions expose all dependencies via their signatures, improving portability and testability.
Testable: provide inputs and assert outputs.
Reasonable: easier to reason about.
Parallelizable: no shared mutable state.
Curry Implementation
// curry :: ((a, b, ...) -> c) -> a -> b -> ... -> c
function curry(fn) {
const arity = fn.length;
return function $curry(...args) {
if (args.length < arity) {
return $curry.bind(null, ...args);
}
return fn.call(null, ...args);
};
}
const match = curry((what, s) => s.match(what));
const replace = curry((what, replacement, s) => s.replace(what, replacement));
const filter = curry((f, xs) => xs.filter(f));
const map = curry((f, xs) => xs.map(f));Currying lets us create reusable, concise functions such as hasLetterR = match(/r/g) and compose them with other utilities.
Composition
const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
const toUpperCase = x => x.toUpperCase();
const exclaim = x => `${x}!`;
const shout = compose(exclaim, toUpperCase);
shout('send in the clowns'); // "SEND IN THE CLOWNS!"Because compose is itself a pure function, it satisfies distributive law and yields consistent results regardless of argument order.
Pointfree Style
Pointfree programming composes operations without explicitly mentioning the data being transformed.
var str = 'Lorem ipsum dolor sit amet';
var splitBySpace = s => s.split(' ');
var getLength = w => w.length;
var getLengthArr = arr => R.map(getLength, arr);
var getBiggerNumber = (a, b) => a > b ? a : b;
var findBiggestNumber = arr => R.reduce(getBiggerNumber, 0, arr);
var getLongestWordLength = R.pipe(splitBySpace, getLengthArr, findBiggestNumber);
getLongestWordLength(str); // 11Using libraries like Ramda, lodash, or Folktale provides ready‑made pointfree utilities.
Reference
Professor Frisby’s Mostly Adequate Guide to Functional Programming (JS translation)
Pointfree JavaScript
Favoring Curry
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.