A Practical Guide To Functional Programming In Javascript

A Practical Guide To Functional Programming In Javascript

Let’s learn and explore some concepts of functional programming in javascript and how it affects the complexity and performance of our programs: It makes codebase easier to read, understand, maintain, and test.

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies.”

C.A.R. Hoare, 1980 ACM Turing Award Lecture

While developing an application or solving a problem in javascript, the complexity and performance are mostly very essential. And the less complexity of the code improves the reusability, testing, and maintenance of the program.

Javascript is a multi-paradigm language that supports using different programming paradigms like Object-oriented, Procedural and functional paradigm which we will be learning about here.

A programming paradigm is a set of principles, techniques, and design concepts that defines the manner in which a program is written or a methodology a programming language adheres to.

Table of contents

  • What is functional programming
  • What functional programming is not
  • Why functional programming
  • Concept of functional programming
  • How to master the use of functional code in projects
  • Conclusion

What is functional programming?

Functional programming is a declarative programming paradigm where you mostly construct and structure your code using expressions and pure functions in which the function takes input as an argument and returns output based on the inputs and doesn’t cause any side-effects.

What functional programming is not

  • Functional programming doesn’t support flow controls like loop statements and conditional statements like If-Else and Switch statements.
  • Mutating objects or data.
  • Using array mutators like pop, push, copyWithin.
  • Writing functions with side effects: impure functions

Why functional programming

  • Pure functions are easier to test.
  • Functional code is easy to debug and with few bugs.
  • The supported javascript features and concepts in functional programming make your code clean and straightforward.
  • Data is immutable.
  • functional codes are modular.

Functional programming is made up of some concepts that actually make your code functional, they bring the benefit of functional code into your application like more readable, usable, manageable, easy to test, and less bug.

Concept of functional programming

For your code to be functional it requires some javascript features or methods to make it possible and gets all the benefits of a functional code. Here let's look at some of those concepts that are associated with functional programming in javascript.

  • First-class functions

Here we talking about one of the very essential features of javascript and the main guy behind functional programming, which is function and it's a group of reusable code that can be called anywhere in your program. A function is said to be a first-class function in javascript because they are treated like any other variable just like data types (string, numbers, etc), and the function can be passed as an argument to other functions that can be returned by another function and can be assigned as a value to a variable.

// function declaration using arrow function
    const addNum = (a,b) => a + b;
    const resultAdd = addNum(4, 6);

    // function declaration using function keyword
    function squareNum(a,b) {
            return a * b
    }
    const resultSquare = squareNum(3, 3)

    // passing functions as arguments to other function
    const totalCalc = (resultAdd, resultSquare) => {
        return resultAdd + resultSquare
    }
  • Pure functions

This is one of the ways to write functions in javascript that can actually make your code functional, pure functions are the core attribute of functional programming in javascript. Pure functions are functions that accept an input and return a value without modifying any data outside its scope(Side Effects). The value is based on given parameters and it brings consistent results.

  //Example of a pure function
    function greetUser (user) {
        return "Hello, good day" + user
    }
    console.log(greetUsers("John"))

    //Example of an impure function
    const user = "John"
    function greetUser (user) {
    return "Hello, good day" + user    
    }
    console.log(greetUser())
  • Higher-order functions

Plain javascript functions are good ways to build abstractions in your code, but sometimes they fail in doing that. It’s very common to want to do something repetitively in your program and you can decide to write a for loop which is not supported in functional programming.

Higher-order functions allow you to abstract over actions in your code, functions that operate on other functions, either by taking them as arguments or by returning them, are called higher-order functions and javascript has some built-in higher-order functions you might be familiar with like Filter, Map, Reduce, and forEach

Here is an example of a higher-order function

  // Define a function that takes a function as an argument
    const fetchSong = () => console.log("Heal the world")

    function playSong(fecthSong){
      return fetchSong()
    }
    playSong()

    // Javascript array methods that are very useful in functional 

    // Array method .filter()

    const randomNum = [1, 5, 15, 20, 40]
    const filteredArray = randomNum.filter(num => {
        return num < 5
    })
    console.log(filteredArray)

    //Array method .map()

    const newFriends = ['Michael', 'Rose', 'Eben', 'Jerry', 'Helen'];
    const announcements = newFriends.map(friend => {
      return friend + ' Is a new friend';
    })
    console.log(announcements);

    // Array method .reduce()

    const arrayOfNumbers = [1, 2, 3, 4];
    const sum = arrayOfNumbers.reduce((accumulator, currentValue) => {  
      return accumulator + currentValue;
    });
    console.log(sum); // 10

    // Array method .forEach()

    const numbers = [28, 14, 90, 17, 27];
    numbers.forEach(number => {  
      console.log(number);
    });
  • Function composition

As the main objective of functional programming is to write clean and maintainable code that breaks down complex problems into a solution, function composition is a concept of chaining two or more functions into a new function and making a single call out of them.

When you chain or compose functions into a single call they serve as a pipeline of specific solutions or behavior. These pipelines then take the result of each function that comprises it and use it as the argument for the next function in the pipeline.

Function composition gives more flexibility on how you work with data while also aiding predictability, readability, testability, etc. Let’s look at some examples of function composition

 //Function composition examples

    let compose = function(fn1, fn2) {
    return fn2(fn1)
    }

    //or

    let compose = (fn1,fn2) => fn2(fn1)
  • Immutability

Immutability is one of the fundamental concepts of functional programming in javascript, it’s a popular term for frontend developers for its very significant use in frameworks like react and redux, where immutability of state is important for the library to work properly.

The concept of immutability is pretty simple and powerful. basically, immutability is when an object's data cannot be changed after its creation.

Immutability is a powerful concept that helps you to prevent the creation of unexpected side effects in your codebase. It makes it easier for you to read and compose your code.

To have immutable data in your application, you need to abandon a few methods, especially array methods such as fill, pop, sort, splice, unshift, reverse, push, etc.

We have a few libraries that can help us with that—for example, Immutable.js. But sometimes we don’t want to use a third-party library, and that’s the moment that we should rely on vanilla JavaScript for it.

 //Immutable data examples
    const fruitStore = ["mango", "apple", "watermellon"]
    let newFruits = [..., fruitStore, "orange"]

    console.log(fruitStore)

    // Mutation example (non functional style)
    const fruitStore = ["mango", "apple", "watermellon"] 
                fruitStore[2] = "orange"

    console.log(fruitStore)
  • Recursion

I have talked about iterating or doing something repetitively in your program, and using loops is not a functional programming perspective. Here we got a concept called Recursion which is a technique for iterating over an operation mostly complex ones by having a function call itself repeatedly until it reaches its base case or a result.

Recursion is a very useful concept in functional programming because it allows for the construction of code that doesn't require creating and maintaining its state with local variables and they are easy to test because the functions are all written in a pure manner.

Note: Recursion can be unoptimized in some cases because it uses more memory. And the function has to add to the stack with each recursive call and keep the values until the call is finished, which can eat away memory until they exceed the capacity of the browser engine. Though there are ways to handle performance and safety in recursion, they are tail call optimization and trampoline functions

```
// a recursive counter function

const countdown = (value) => {
    if (value > 0) {
        console.log(value);
        return countdown(value - 1);
    } else {
        return value;
    }
};
countdown(10);
```
  • Closure

Dealing with variable scope and its lexical environment is a very important technique in functional programming, and javascript support this feature with a concept called closure.

A closure is simply a function that remembers its outer variables and can access them, it brings in the combination of function and its lexical environment within which the function was declared.

Closure lets you get some features of object-oriented programming in functional programming with a very useful case that lets you associate data with a function that operates on that data.

Here is an example of closure

//Closure example - variable is updated in the Lexical Environment where it lives.
function makeCounter() {
    let count = 0
return function() {
    return count++
}
}

let counter = makeCounter()
console.log(counter())

//If we call counter() multiple times, the count variable will be increased to 2, 3 
//and so on, at the same place.
  • Currying

As one of the main aim of functional programming is writing readable and easy to debug code and also dealing with avoiding repetition of code javascript support a useful technique called currying.

Currying deals with transforming functions of multiple arguments into several functions of a single argument in sequence. A curried function takes multiple arguments one at a time, for example, a function with 3 parameters the curried function will take one argument and return a function that takes the next argument, which returns a function that takes the third argument and the last functions return the result applying the function to all of its arguments. Let’s look at a practical currying function by building a simple pizza recipe app

//Currying function

const pizzaMaker = (ingredient1) => {
    return (ingredient2) => {
        return (ingredient3) => {
            return `${ingredient1}, ${ingredient2}, ${ingredient}`
        }    
    }
}

const spicyPizza = pizzaMaker("Bacon")("Tomatos")("peperoni")
console.log(spicyPizza)

//we can refactor to have a more functional coding style using arrow functions

const makePizza = ingredient1 => ingredient2 => ingredient3 => 
            `${ingredient1}, ${ingredient2}, ${ingredient}`

const myPizza = makePizza("Flour")("Onion")("Tomatos")

Tips to master the use of functional code in projects

  • Always write pure functions in your code with fixed output for fixed inputs, and no side effects.
  • Write your code in declarative styles and not imperative like a step-by-step approach.
  • Avoid mutating state and data in your code.
  • Use expressions and declarations
  • Use javascript functional methods like filter(), map(), and reduce() in performing iteration.

Conclusion

Functional programming is becoming one of the ways of writing modern robust programs and having fun well at it with less stress for debugging and easy to maintain code. With lots of support from the ecosystem and industry experts, there are lots of resources to learn from and it's adopted by some big open source projects like react.

I hope you enjoy exploring some practical guides and features to kickstart or be better at writing your programs in functional styles it may be a completely new programming paradigm, but I hope you will give it a chance. Thanks for reading follow for more articles in javascript, react, and web 3.0.