Functional programming is a trending topic in modern web development. It is all about designing the application architecture as a combination of simple functions to write more extensible code. It allows you to simply swap any function without breaking another part of the program and makes it easier to understand and debug the program.
In this article, I will discuss seven functional programming techniques that you can use with JavaScript to give you a better understanding of how to apply functional programming in your web development projects.
Pure functions return the same result if we send the same parameters. They merely return the results of their operation and don’t look at anything outside the scope. Other than returning their return value, pure functions do not affect anything.
const helloWorld = (name) => `Hi ${name}`; helloWorld(‘Piumi’);
A side effect is a concept in functional programming that occurs when a function not only returns a value but also alters components in the background. When a function executes, it has the potential to modify something. It is best to minimize side effects to the greatest extent possible. This is where pure functions are a great option because they have minimal side effects.
We should always strive to keep the scope of each variable as small as possible by localizing variables as much we can when creating them. Pure functions do not depend on anything besides their parameters and as a result their behavior is foreseeable. If the parameters are the same, the result will be the same. This greatly improves the testability of your code.
A distinctive feature of pure functional programming is immutability. You will have to throw out standard looping methods such as for, while, and do-while to avoid mutating variables after they have been initialized (e.g., loop counters). Instead, JavaScript offers higher-order functions like map, filter, reduce, and foreach to abstract the iterative processes.
Let’s consider a few examples with foreach, map, filter, and reduce functions.
foreach(): A function is called for each element in an array.
let sum = 0; const numbers = [10, 25, 73, 84]; numbers.forEach(addNumbers); function addNumbers(number) { sum += number; }
map(): Each array item is mapped to a function, and the return values of the function calls help us to create a new array. A mapper function takes an array item as input and returns the output.
array.map(mapper)
filter(): Filters the array based on a condition. The condition, in this case, is a function that gets every element in the array and decides whether or not to hold it, returning the truthy Boolean value.
array.filter(condition);
reduce(): A function that reduces an array to a single value. In the following code snippet, the parameter reducer is a function that returns the new value from the accumulated value and the next item in the array. It is called this way for each value in the array, one by one.
array.reduce(reducer);
The following example shows how we can use each of the above functions.
const computers= [ { make: 'ASUS', model: 'CT-0019', type: 'PC', price: 25000}, { make: 'DELL', model: 'DX-001', type: 'PC', price: 16800}, { make: 'ASUS', model: 'CT-0011', type: 'LAPTOP', price: 79800}, { make: 'ASUS', model: 'CT-0209', type: 'LAPTOP', price: 65400}, { make: 'DELL', model: 'DX-005', type: 'PC', price: 34500}, { make: 'DELL', model: 'DX-001', type: 'LAPTOP', price: 35000}, { make: 'HP', model: 'HP-003', type: 'PC', price: 36500}, { make: 'HP', model: 'HP-025', type: 'PC', price: 50000}, { make: 'DELL', model: 'DX-004', type: 'LAPTOP', price: 87000}, { make: 'HP', model: 'HP-324', type: 'PC', price: 46000} ]; const averageComputerPrice = computers .filter(c => c.type === 'LAPTOP') .map(c => c.price) .reduce((sum, price, i, array) => sum + price / array.length, 0); console.log(averageComputerPrice);
Getting rid of loops makes your code more declarative and easier to understand by eliminating the need to keep track of loop counters and array length. As the loop’s body is contained within a function, each loop value is correctly bound to the callback’s parameter, preventing unexpected JavaScript scoping bugs.
In JavaScript, function chaining is a pattern which allows calling multiple functions on the same object in sequential order. We can invoke multiple functions using the same object reference with this technique. It makes the code more readable and reduces the amount of redundant code.
In scenarios where we require multiple functions to complete all the functionality associated with an entity, those functions can be written in a way that allows them to be chained together to achieve the desired results.
We can achieve the same functionality in JavaScript by returning the current object from the executing function. When a function is invoked on an object, the same object is returned, allowing other functions to be called and the task to be followed.
var obj = { output: 0, addNumber: function(p, q) { this.output= p + q; return this; }, multiplyNumber: function(p) { this.output= this.output * p; return this; } }; obj.addNumber(10, 20).multiplyNumber(10) console.log(obj.output)
In the above code sample, as the addNumber function reflects the current obj object, the returned value contains additional functions. We’re running the second function, multiplyNumber, on the same object in order to chain them together.
This method of function chaining results in very declarative code, paving the way for abstraction that focuses on what the program should do rather than how it does it.
Currying is the process of breaking down a multi-argument function into a sequence of unary (single argument) higher-order functions. In other words, a function with three parameters, f(p,q,r), is enhanced structurally to three functions that work with one argument at a time, f(p) -> f(q) -> f(r).
Consider the following example.
function fsum (a,b) { return a+ b } //Currying function fsum_curry (a) { return function(b) { return a + b } } fsum(10, 2) // 12 fsum_curry(10)(2) // 12
The benefit of currying is memoization. We can now memoize certain arguments in a function call to reuse them later without having to duplicate and recompute.
We often confuse partial application and currying even though they are two different concepts. For example, a curried function is always a curried function, even if we don’t give any arguments to it. Partial application occurs when we give some of the arguments of a function to it but not all of them. Currying is a popular method for performing partial application, but it isn’t the only option.
In partial application, the instantiation of some of the function’s parameters is delayed. This can come in handy if we need to parameterize some procedures for later use.
function havingMeal(verb) { // Outer function return function(input) { // Inner function return "I'm " + verb + " " + input + " ." } } // Partially apply 'havingMeal' var haveLunch = havingMeal('eating') var haveTea = havingMeal('drinking') haveLunch('lunch') //"I'm eating lunch." haveTea('coffee') //"I'm drinking coffee."
Following the principle of referential transparency, it can be also written as follows.
haveLunch(‘lunch’) === prepareLunch(‘eating’)(‘lunch’)
Composition is a method of combining the execution of several smaller functions into one. It’s the process of connecting the output of one function to the input of another, resulting in the creation of a whole new function.
Relationships are made evident through composition. Once you understand the concept and begin to apply it, you’ll notice that it aids you in writing more well-structured and understandable functions. Also, you can achieve separation of concerns, making your code cleaner.
const split = (string) => string.split('_').join(' '); const lowerCase = (string) => string.toLowerCase(); console.log(lowerCase(split('APPLE_TREE'))); //apple tree
Recursion is a self-calling mechanism, meaning that a recursive function is a function that calls itself. In software development, recursion helps address issues such as the traversal of trees or mathematical progressions like the Fibonacci sequence. Recursion has become the de facto iteration technique in functional programming because it is particularly efficient at traversing any linear data structure, like arrays.
function factorial(n, product = 1) { if (n === 0) { return product; } return factorial(n - 1, product * n) }
The main advantage of using recursion is that it allows you to loop in an immutable manner because there is no explicit loop counter to update. As a result, the task of traversing an array’s elements is completely delegated to the language runtime.
Functional programming is getting more popular among JavaScript developers day by day as it simplifies the implementation of complex applications, making them more readable, testable, and comprehensible.
So, I invite you to use the seven JavaScript functional programming techniques discussed above to enhance your coding skills and build robust, extensible applications.
Thank you for reading!
Syncfusion Essential JS 2 is the only suite you will ever need to build an app. It contains over 65 high-performance, lightweight, modular, and responsive UI components in a single package. Download a free trial to evaluate the controls today.
If you have any questions or comments, you can also contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!