Why Do You Need to Know About Functional Programming?

Why Do You Need to Know About Functional Programming?

The programming paradigm that simplifies your code
Ferenc Almasi • 🔄 2021 November 11 • 📖 11 min read

When I first started learning about functional programming, I had a hard time wrapping my head around it. I understood the concept and the main principles but I lacked the practical knowledge. With this tutorial, I want to cover not just the concepts, but give you examples and show you how you can apply the functional programming paradigm to your own code.

Let’s first start by defining what is functional programming.

Functional programming is a programming paradigm.

Just like object-oriented programming, functional programming has its own concepts. For example, everything revolves around being pure — functions always return the same output given the same input. They have no side effects, meaning they don’t alter or mess with any data outside of their scope.

It also advocates being immutable — once something is created, it cannot be changed. We may also often hear that functional programming uses a declarative approach as opposed to the imperative approach that is also used by the object-oriented paradigm.

These are just some of the concepts that make up functional programming. But why are these principles important? What can they give us?

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

Why Functional Programming Can Benefit Us?

It’s important to mention that functional programming is not a new paradigm. In fact, Lisp which was developed in the late 1950s was heavily functional. Still, we can benefit from it today for a couple of reasons.

One of them is that it will make your code easier to reason about. It focuses more on the “What is your program doing?” instead of “How does it do its thing?” — meaning you go with a declarative approach opposed to imperative implementations. To demonstrate, take a look at the two examples below.

In the first example, you focus on how the program is doing its thing, while in the second, you focus on what the program is doing:


for (let i = 0; i < products.length; i++) {
    products[i].price = Math.floor(product.price);
Copied to clipboard!


products.map(product => {
    product.price = Math.floor(product.price);

    return product;
Copied to clipboard!

The two implementations are doing the same thing; modifies an array so we have rounded numbers for each product. For this small example, it may seem like you are writing more code. But behind the scenes, map will also return you a brand new array, meaning your original products will be kept intact. This is immutability in action.

It also makes your code more easily testable as it focuses on small contained functions called pure functions. As mentioned before, these functions are deterministic. We can guarantee that if we keep passing it the same value, we get the same output.

In the end, functional programming makes your code easier to reason about. It makes it easier to read and follow the process you took and makes your application less prone to bugs. In case something still goes wrong, it’s easier to troubleshoot since your code is more concise.

To demonstrate how you can use functional programming in action, I’ve prepared some code examples that show you how to be declarative.

Declaring What You Mean

One of the best ways to start is by looking at array functions. Higher-order array functions are a good example of the functional programming approach.

Array functions

I have an entire article describing some of the array methods mentioned here, which you can check in the link below:

The Power of Higher-Order Array Functions

but let’s quickly go through some of the more important ones and see what they do and how they shorten our code to make it more readable.

Used for finding a specific element that passes the test, returns the first match

// Even if we have multiple products that are on sale, it will only return the first match
products.find(product => product.onSale);
Copied to clipboard!

Used for returning the elements that pass the test, returns every match

// This will return every product that is on sale
products.filter(product => product.onSale);
Copied to clipboard!

If every element meets the criteria, it will return true

// Every product should have a name so we get back true
products.every(product => product.name);
Copied to clipboard!

If at least one element matches the criteria, it will return true

// If we have at least one product that is on sale, we get back true.
products.some(product => product.onSale);
Copied to clipboard!

Used for transforming an array, gives back a new one

// Rounding prices for products
products.map(product => {
	product.price = Math.floor(product.price);

	return product;
Copied to clipboard!

Used for producing a single value from an array

// Sum the prices of each product
products.reduce((accumulated, product) => accumulated + product.price, 0);
Copied to clipboard!

You can already see how these array methods can shorten our code instead of using for loops, but we can make them even more powerful by chaining them. Most of these functions return an array, on which we can call another method and keep going until we get the desired result.

Function Chaining

Function chaining is another great concept. It makes your code more reusable and again, reduces the noise and creates a shorter, more concise code that is both more readable, and in case of any bugs, it’s easier to debug.

In the example below, you’ll see that since each function call returns an array, you can keep calling new functions on them to create a chain.

const round = (num) => Math.floor(num);
const isDivisibleByTwo = (num) => num % 2 === 0;
const add = (accumulated, num) => accumulated + num;

const numbers = [0, 1.2, 2.4, 3.6, 4.8, 5, 6.2, 7.4, 8.6, 9.8];

const sum = numbers.map(round)
                   .reduce(add, 0);
Copied to clipboard!

Instead of using three different for loops to get the desired value, we can simply call functions one after another and get it done in 3 lines.

Last but not least, libraries can help you avoid writing down the same things over and over again — and reinventing the wheel — by introducing helper functions for commonly occurring problems.


There are many libraries out there that are following the functional programming paradigm. Some of the more well known are Lodash and Ramda. To give you some visual differences between the two let’s take a look at how you can retrieve nested properties in each — a commonly occurring problem. If one of the objects does not exist, we will get an error saying:

Getting cannot read property error in Chrome

Let’s say we have a user object where we want to get their email address:

const user = {
    name: 'John Doe',
    dob: '1999.01.01',
    settings: {
        email: '[email protected]'
Copied to clipboard!

Lodash uses underscore

// returns "[email protected]" || undefined
_.get(user, 'settings.email');
Copied to clipboard!

Ramda uses R

// returns "[email protected]" || undefined
R.path(['settings', 'email'], user);
Copied to clipboard!

In each library, we can avoid getting an error if the parent of email does not exist. Instead it silently fails with an undefined.

Now you have a better understanding of how to be more declarative. What are some other important concepts in functional programming? — It’s in the name, it is functions.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

Functions In Functional Programming

Functions are not only an essential part of functional programming but of JavaScript as well. They can help you break up your code to smaller, more digestible pieces. It increases readability and makes your code more easily testable by separating your code into smaller sections, often called components.

There are many concepts of how we can use functions to our own advantage. Let’s see some of the more commonly occurring definitions you can find in functional programming.

Pure functions

As discussed previously, pure functions don’t depend on any data other than what is passed into them. They also don’t alter any data other than what they returned.

To give you a practical example for pure functions, think of the Math object:

// This will return ??? - we don't know

// This will return 10, no matter what.
Math.max(10, 5);
Copied to clipboard!

Here, Math.random is impure since it always returns a different value, even if we were to pass it the same input. Math.max however is a pure function since it will return the same output given the same input.

We need to note that in case our function doesn’t have a return value, it is not pure.

First-class functions

In JavaScript and other functional languages, functions can also be assigned to variables and you can pass them around, just like they were variables.

const greet = function () {

// The greet variable is now a function, we can invoke it
Copied to clipboard!

Higher-order functions

A higher-order function is nothing more than a simple function that takes in another function as one of its arguments. Functions that return another function are also called higher-order functions.

A great example for higher-order functions are previously discussed array functions such as filter or map.

Function composition

Function composition is all about combining functions to form brand new functions.

For example, Ramda has the compose function which takes in a list of functions as arguments and returns a function. You can call this with the input for which you want to apply the series of functions.

// Produces 7.283185307179586
Copied to clipboard!


Currying is a technique where you call a sequence of functions with one argument instead of calling one function with multiple arguments. Each function returns another function. The function at the end of the chain returns the actual expected value.

// Instead of
const add = (a, b, c) => a + b + c;

add(2, 2, 2);

// Currying does
const curry = (a) => {
    return (b) => {
        return (c) => {
            return a + b + c;

Copied to clipboard!


Recursion happens when a function keeps calling itself until some condition is met. In the example below, we are counting down from 100.

finalCountdown = (number) => {
    // If we don't specify an exit criteria, the number will continue into minus until the browser crashes
    if (!number) {

    console.log(`It's the final countdown! - ${number}`);

    finalCountdown(number - 1);

// Will print out numbers from 100 till 1
Copied to clipboard!

It’s important to specify an exit condition otherwise you will create an infinite loop that eventually crashes the browser.

Now if you feel like you are starting to become overwhelmed by the amount of information, don’t worry, it’s a good sign that means you are expanding your knowledge. There are only two more important concepts we need to cover. They go hand in hand. They are immutability and side effects.


When we talk about immutable variables and objects, we simply mean that once declared, their value can’t be changed. This can reduce the complexity of your code and make your implementation less prone to errors.

To demonstrate immutability through an example, let’s say you have an array where you need to remove the first item. Take a look at the differences below:

const presents = ['🎁', '📦', '🎀', '💝', '🎄'];

// --- Mutable solution ---

// we get back 🎁
// and presents will be equal to ['📦', '🎀', '💝', '🎄'];

// --- Immutable solution ---

// newPresents will be equal to 📦 🎀 💝 🎄
// and presents will be still equal to ['🎁', '📦', '🎀', '💝', '🎄'];
const newPresents = presents.slice(1);
Copied to clipboard!

In the first example, we modify the original array with the shift function. If we want to achieve the same but keep the original array intact, we can use slice instead. This way you can avoid having unforeseen bugs in your application where you unintentionally modify data that should be kept in pristine condition.

One downside of immutability is performance. If you create too many copies you will run into memory issues so in case you operate on a large data set, you need to think about performance.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript

What Are The Side Effects?

We also need to talk about side effects not because they are part of the functional programming paradigm but because they happen regardless of what programming pattern you take. They are an important part of any program and you need to know when and why they happen.

So what are side effects? — Side effects can occur when a function is impure, therefore it does not necessarily return the same output given the same input. One commonly occurring example would be a network request. No matter what is the input, you can get back anything from 200 (OK) to 500 (Internal Server Error).

So you can’t avoid having side effects and your goal shouldn’t be to eliminate them entirely, but rather to be deliberate. Deliberate about why and when they happen.


Functional programming is a great way to organize your code in a better way. There are other programming paradigms out there like object-oriented programming. So what should you use, which is better?

There’s really no answer, it depends on your situation and there’s no one above the other. You can also combine multiple paradigms together so it’s not a “one way or the other”.

Thank you for taking the time to read this article, happy coding!

Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Unlimited access to hundred of tutorials
  • check Access to exclusive interactive lessons
  • check Remove ads to learn without distractions
Become a Pro