Functional Programming in JavaScript
Master functional programming concepts: pure functions, immutability, higher-order functions, and functional composition.
Topics Covered:
Prerequisites:
- JavaScript Functions and Scope
Video Tutorial
Overview
Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions. Many React patterns are inspired by functional programming. This tutorial covers pure functions, immutability, higher-order functions, function composition, currying, and recursion. Understanding functional programming helps you write better React code.
Pure Functions
Pure functions always return the same output for the same input and have no side effects. Pure Function Characteristics: • Same input → same output • No side effects • Doesn't depend on external state • Predictable and testable Benefits: • Easier to test • Easier to reason about • Can be memoized • Parallelizable
// ✅ Pure function
function add(a, b) {
return a + b;
}
// Same input always gives same output
console.log(add(2, 3)); // 5
console.log(add(2, 3)); // 5
// ❌ Impure function (depends on external state)
let counter = 0;
function increment() {
counter++;
return counter;
}
// ❌ Impure function (side effect)
function logMessage(msg) {
console.log(msg); // Side effect: logging
return msg;
}
// ✅ Pure function (no side effects)
function formatMessage(msg) {
return `[LOG] ${msg}`;
}
// Pure functions in React
function Button({ label, onClick }) {
// Pure component - same props → same output
return <button onClick={onClick}>{label}</button>;
}
// Impure component (uses external state)
function Clock() {
const [time, setTime] = useState(new Date());
// Uses state, but component itself is still "pure" in React's sense
return <div>{time.toString()}</div>;
}Pure functions are predictable and testable. They always return the same output for the same input and have no side effects. React components should be pure when possible.
Immutability
Immutability means data cannot be changed after creation. Instead, create new data structures. Immutability Benefits: • Prevents accidental mutations • Easier to track changes • Better for React (re-renders) • Enables time-travel debugging In JavaScript: • Use const for variables • Create new objects/arrays • Use spread operator • Use immutable libraries
// ❌ Mutation
const user = { name: "Alice", age: 30 };
user.age = 31; // Mutates original object
// ✅ Immutability
const user = { name: "Alice", age: 30 };
const updatedUser = { ...user, age: 31 }; // New object
// ❌ Array mutation
const numbers = [1, 2, 3];
numbers.push(4); // Mutates array
// ✅ Immutable array operations
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4]; // New array
// Immutability in React
function Component() {
const [items, setItems] = useState([1, 2, 3]);
const addItem = (item) => {
// ✅ Create new array
setItems([...items, item]);
// ❌ Don't mutate
// items.push(item);
// setItems(items);
};
const updateItem = (index, newValue) => {
// ✅ Create new array with updated item
setItems(items.map((item, i) =>
i === index ? newValue : item
));
};
}Immutability prevents bugs and makes code easier to reason about. Always create new objects/arrays in React instead of mutating existing ones. Essential for React's re-rendering.
Function Composition
Function composition combines simple functions to build complex ones. Composition: • Combine functions • Output of one is input of next • Build complex behavior from simple parts • More readable than nested calls Benefits: • Reusable functions • Easier to test • More readable • Follows single responsibility
// Simple functions
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
const square = x => x * x;
// Composition
const addThenSquare = (a, b) => square(add(a, b));
console.log(addThenSquare(2, 3)); // 25
// Compose utility
const compose = (...fns) => (value) =>
fns.reduceRight((acc, fn) => fn(acc), value);
const pipe = (...fns) => (value) =>
fns.reduce((acc, fn) => fn(acc), value);
// Usage
const process = pipe(
(x) => x + 1,
(x) => x * 2,
(x) => x.toString()
);
console.log(process(5)); // "12"
// Composition in React
const withAuth = (Component) => (props) => {
if (!props.isAuthenticated) {
return <Login />;
}
return <Component {...props} />;
};
const withLogging = (Component) => (props) => {
console.log("Rendering:", Component.name);
return <Component {...props} />;
};
const EnhancedComponent = withLogging(withAuth(MyComponent));Function composition combines simple functions to build complex behavior. Makes code more reusable and readable. Used in React for higher-order components and hooks.
Currying
Currying transforms a function with multiple arguments into a sequence of functions with single arguments. Currying: • Function returns another function • Each function takes one argument • Partial application • More flexible function usage Benefits: • Partial application • Function reuse • More flexible APIs • Functional composition
// Regular function
function add(a, b, c) {
return a + b + c;
}
// Curried function
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
// Arrow function currying
const curriedAdd = a => b => c => a + b + c;
console.log(curriedAdd(1)(2)(3)); // 6
// Partial application
const add5 = curriedAdd(5);
const add5And10 = add5(10);
console.log(add5And10(15)); // 30
// Currying utility
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
};
}
const curriedMultiply = curry((a, b, c) => a * b * c);
console.log(curriedMultiply(2)(3)(4)); // 24
console.log(curriedMultiply(2, 3)(4)); // 24
console.log(curriedMultiply(2)(3, 4)); // 24
// Currying in React
const handleChange = (field) => (event) => {
setFormData({
...formData,
[field]: event.target.value
});
};
<input onChange={handleChange("name")} />
<input onChange={handleChange("email")} />Currying transforms multi-argument functions into sequences of single-argument functions. Enables partial application and more flexible function usage. Useful in React for event handlers.
Conclusion
Functional programming provides powerful patterns for writing maintainable code. You've learned pure functions, immutability, composition, and currying. These concepts are fundamental to React development. Practice these patterns and apply them in your React applications for cleaner, more testable code.