A pure function is a function that, given the same input, will always return the same output and has no side - effects. Side - effects include modifying global variables, making API calls, or changing the state of an object passed as an argument.
// Pure function example
function add(a, b) {
return a + b;
}
const result = add(3, 5);
console.log(result); // 8
Immutability means that once a data structure is created, it cannot be changed. Instead of modifying an existing object or array, new objects or arrays are created.
// Immutable array example
const originalArray = [1, 2, 3];
const newArray = [...originalArray, 4];
console.log(originalArray); // [1, 2, 3]
console.log(newArray); // [1, 2, 3, 4]
A higher - order function is a function that either takes one or more functions as arguments or returns a function.
// Higher - order function example
function multiplyBy(factor) {
return function (number) {
return number * factor;
};
}
const double = multiplyBy(2);
console.log(double(5)); // 10
A closure is a function that has access to the variables in its outer (enclosing) function’s scope, even after the outer function has finished executing.
// Closure example
function outerFunction() {
const message = 'Hello';
function innerFunction() {
console.log(message);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // 'Hello'
Function composition is the process of combining two or more functions to create a new function.
// Function composition example
function addOne(x) {
return x + 1;
}
function double(x) {
return x * 2;
}
function compose(f, g) {
return function (x) {
return f(g(x));
};
}
const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(3)); // (3 + 1) * 2 = 8
Currying is the process of converting a function that takes multiple arguments into a sequence of functions that each take a single argument.
// Currying example
function add(a, b) {
return a + b;
}
const curriedAdd = a => b => a + b;
console.log(curriedAdd(3)(5)); // 8
JavaScript provides many built - in array methods that follow functional programming principles, such as map
, filter
, and reduce
.
// Array methods example
const numbers = [1, 2, 3, 4, 5];
const squared = numbers.map(num => num * num);
const evenNumbers = numbers.filter(num => num % 2 === 0);
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(squared); // [1, 4, 9, 16, 25]
console.log(evenNumbers); // [2, 4]
console.log(sum); // 15
We can use functional programming techniques to transform objects.
// Object transformation example
const person = {
name: 'John',
age: 30
};
const newPerson = {
...person,
age: person.age + 1
};
console.log(person); // { name: 'John', age: 30 }
console.log(newPerson); // { name: 'John', age: 31 }
When working with functional programming, it’s important to handle errors in a functional way. One approach is to use the try...catch
block inside a pure function.
// Error handling example
function safeJsonParse(jsonString) {
try {
return JSON.parse(jsonString);
} catch (error) {
return null;
}
}
const validJson = '{"key": "value"}';
const invalidJson = 'not a valid json';
console.log(safeJsonParse(validJson)); // { key: 'value' }
console.log(safeJsonParse(invalidJson)); // null
Write functions with descriptive names and keep them small and focused. This makes the code easier to understand and maintain.
// Readable code example
function getFullName(firstName, lastName) {
return `${firstName} ${lastName}`;
}
const fullName = getFullName('Jane', 'Doe');
console.log(fullName); // 'Jane Doe'
Functional programming in JavaScript offers many benefits, including code that is easier to understand, test, and maintain. By understanding and applying the fundamental concepts, usage methods, common practices, and best practices outlined in this blog post, you can write more robust and efficient JavaScript code.