Functional programming in JavaScript

Functional programming in JavaScript

It's a programming paradigm that focuses on the use of functions as a primary building block of software. In JavaScript, functional programming is supported natively, which means that you can use it without any additional libraries or tools.

(And all the code that you are about to see here it's in this repo)

Now, here are some of the key concepts of functional programming in JavaScript:

Pure functions

A pure function is a function that always returns the same output for the same input, and does not have any side effects. In other words, it does not modify any external state or data. Pure functions are predictable, easy to test, and can be composed together to create more complex functions.

/* -------------------------------------------- */
/*                Pure functions                */
/* -------------------------------------------- */
const double = x => x * 2;
let value = 2;
console.group('No matter the time executes the output will always be the same \ngiven the same value')
console.log(double(value))
console.log(double(value))
console.log(double(value))
console.log(double(value))

value = 3
console.log(double(value))
console.log(double(value))
console.log(double(value))

value = 12
console.log(double(value))
console.log(double(value))
console.log(double(value))

value = 234
console.log(double(value))
console.log(double(value))
console.log(double(value))
console.groupEnd()

In contrast, you can see what a not pure function would look like:

/* ----------- Not so pure functions ---------- */
const ran = x => x * Math.random();

console.group('It will always change no matter if is the same input')
console.log(ran(value))
console.log(ran(value))
console.log(ran(value))
console.groupEnd()

Immutability

In functional programming, immutability is the idea that data should not be modified once it is created. Instead, new data is created based on the old data. This allows for more predictable and maintainable code.

Higher-order functions

A higher-order function is a function that takes one or more functions as arguments or returns a function as its result. Higher-order functions are used extensively in functional programming.

/* -------------------------------------------- */
/*            Higher Order Functions            */
/* -------------------------------------------- */
function triple(x) {
    return x * 3;
}
const numbers = [1, 2, 3, 4, 5, 16, 27,];

const result1 = numbers.map(y => y * 3);
const result2 = numbers.map(triple);
// const result3 = numbers.map(triple()) // map will execute the function, not you. You only declare it not call it
// result1 === result2
// result2 !== result3

// higher order function can also be
// a function which returns another function

console.log("Higher order results", result1, result2, /* result3 */);

Recursion

Recursion is a technique in which a function calls itself until a stopping condition is met. In functional programming, recursion is used instead of loops to iterate over data structures.

You can see that in this code of a deep copy of an object of JavaScript:

/* --------------- Deep copy --------------- */
function isObject(element) {
    return typeof element === "object";
}
function isArray(element) {
    return Array.isArray(element);
}

function deepCopy(element) { // you can do this but with Freeze if you like (deepFreeze)
    const isObj= isObject(element);
    const isArr = isArray(element);
    let copy;

    if (isArr) {
        copy = [];
    } else if (isObj) {
        copy = {};
    } else {
        return element;
    }

    for (let key in element) {
        const inKey = element[key];
        const isKeyObject = isObject(inKey);

        if (isKeyObject) {
            copy[key] = deepCopy(inKey)
        } else {
            if (isArr) {
                copy.push(inKey);
            } else {
                copy[key] = inKey;
            }
        }
    }
    return copy;
}

const objD1 = deepCopy(objA2);
console.group("Deep Copy")
console.log(objD1, objA2)
objD1.a2 = 75950;
objD1.e2.f2 = 6905589
objA2.k2();
objD1.k2();
console.log("After modifications")
console.log(objD1, objA2)
console.groupEnd("Deep Copy")

Function composition

Function composition is the process of combining two or more functions to create a new function. This allows for more complex functionality to be built from simpler building blocks.

Closures

A closure is a function that has access to variables in its outer (enclosing) scope, even after the outer function has returned. This is possible because the variables are still being referenced by the inner function, and are not eligible for garbage collection. Closures are used extensively in functional programming and can be used to create private variables and functions, as well as to create higher-order functions. Here is an example of a closure in JavaScript:

/* -------------------------------------------- */
/*                   Closures                   */
/* -------------------------------------------- */
const rememberToSum = a => b => a + b;
function rememberToSum(a) {
    return function (b) {
        return a + b;
    }
}
const returnedSum = rememberToSum(5);
console.log(returnedSum(5))

Currying

Currying is a technique in which a function that takes multiple arguments is converted into a sequence of functions that each take a single argument. This allows for more flexible function composition and partial function application. In JavaScript, you can use the curry function from the popular lodash library to curry functions. Here is an example of using curry to create a curried function:

/* -------------------------------------------- */
/*                   Currying                   */
/* -------------------------------------------- */
function notCurredSumOfThree(a, b, c) {
    return a + b + c;
}
function sumOfThree(a1) {
    return function (b2) {
        return function (c3) {
            return a1 + b2 + c3;
        }
    }
}
const arrowSumOfThree = a => b => c => a + b + c; 

console.log(notCurredSumOfThree(1, 2, 3), sumOfThree(1)(2)(3), arrowSumOfThree(1)(2)(3));

Overall, functional programming in JavaScript can lead to more maintainable, predictable, and reusable code. It may take some time to get used to the functional programming paradigm, but it is worth exploring for any serious JavaScript developer.


Well, that's it for now. I hope it was useful for you. Comment if you have any other suggestions or something to add, I'll be reading you.

Follow me on Twitter, LinkedIn, Instagram, Github, Medium (For more opinion-based posts), and here on Hashnode and my Hashnode blog.

Have a nice day and until next time. Bye.