Understanding Higher-Order Functions in Javascript

Understanding Higher-Order Functions in Javascript

ยท

5 min read

Functions in Javascript

Let's first understand function in javascript.

In javascript, functions are First-Class Citizens. What First-Class Citizens mean?

  • Functions can be assigned to variables.
  • Functions can be passed as arguments to another function.
  • Functions can be returned from any other function.

Example

1. Function assigned to variables.
// assign to variable
const varibleFunc = function() {
    console.log("JavaScript ๐Ÿ•")
}
varibleFunc() //JavaScript ๐Ÿ•
2. Functions passed as an arguments to another function.
// passing function as arrguments
function morning(name) {
    return `Good Moring ${name}`
}

function greet(name, func) {
    return func(name)
}
console.log(greet("John Snow", morning)) //Good Moring John Snow ๐ŸŒ„
3. Function returned from another function.
function outer() {
    function inner(name){
        return `Hello ${name} ๐ŸŒ`;
    }
    return inner;
}
const func = outer();
console.log(func("World")) // Hello World ๐ŸŒ

Now let's understand Higher-Order Function.

What are Higher Order Functions?

A function that takes another function as an argument or returns a function is known as the Higher-order function.

Why use the Higher-order function?

It allows us to write smaller functions, that take care of one piece of logic. This helps is simple and flexible code. This also helps in testing and debugging code.

Example

Passing function as an argument
const numbers = [2, 3, 4, 5, 6];

const square = (value) => {
    return value * value
}

const cube = (value) => {
    return value * value * value
}
// higher order function
const calculate = (arr, logic) => {
    let result = [];
    for(let i=0; i<arr.length; i++) {
        result.push(logic(arr[i]))
    }
    return result
}

console.log(calculate(numbers, square)) //[ 4, 9, 16, 25, 36 ]
console.log(calculate(numbers, cube)) //[ 8, 27, 64, 125, 216 ]

Let's understand code-

Notice that calculate() is higher-order function. It takes another function as an argument. calculate function takes numbers array and square, cube functions as an argument and returns squares and cubes of numbers.

We made square and cube logic functions whose only work is to perform a specific operation. If we want to perform another operation on the numbers array, we only need to create another callback function that would operate.

square and cube functions are callback function as they are passed to another function. (In this case calculate() function.) This function takes care of one piece of logic. sqaure() returns square of number and cube() returns cube of numbers.

Built in Higher-Order functions

Javascript also has built-in Higher-order functions. map, filter, reducer and forEach are built-in higher-order functions. These are array methods in javascript.

map()

  • Array.prototype.map() creates a new array populated with results returned from callback function passed to it.
  • This method doesn't change the original array.
  • Callback function passed to the map is executed for every element in the array and returns the expected value.
  • If nothing is returned from the callback function then undefined will be returned and added to the newly created array.

Read more on MDN Docs

Example

const numbers = [2, 3, 4, 5];
// returns new array
const squares = numbers.map(num => num * num)
console.log(squares)  //[ 4, 9, 16, 25 ]

// no value is returned from callback function
const cubes = numbers.map(num => {
    let cube = num * num * num
})
console.log(cubes)  //[ undefined, undefined, undefined, undefined ]

filter()

  • Array.prototype.filter() takes each element from an array and applies conditional statement. If this condition returns true, the element gets pushed to the output array.
  • Like map(), filter() doesn't change original array.

Read more on MDN Docs

Example

const numbers = [2, 3, 4, 5, 6, 8, 9];

const smallerThanFive = numbers.filter(num => num < 5)
console.log(smallerThanFive);  //[ 2, 3, 4 ]

reduce()

  • Array.prototype.reduce() method takes the reducer function and executes this reducer function on each element of the array, resulting in a single output value.

Syntex

array.reduce(callbackFn, initialValue)

Let's see an example-

const numbers = [9, 8, 7, 6, 5, 4, 3, 2, 1];

const total = numbers.reduce((accumulator, currentElement) => accumulator+ currentElement)
console.log(total)  //45

// OR
function calculate(accumulator, currentElement) {
  return accumulator + currentElement
}

const total = numbers.reduce(calculate);
console.log(total)  //45

How does it work?

First Iteration

  1. The accumulator is initialized with the first element in the array. i.e 9 in this case.
  2. The currentElement is to 8. i.e second element in the array.
  3. Then In the reducer function, accumulator + currentElement, 9 + 8 = 17 is returned and assigned to accumulator .

Second Iteration

  1. The accumulator value is 17, (the result of the first iteration).
  2. Now, the currentElement is 7. it's the next element of the array.
  3. Again, accumulator + currentElement, 17 + 7 = 24 is returned and assigned to accumulator.

These iterations continue till there's no element to iterate over. The accumulator value is returned and stored to the total variable.

Passing initialValue

We can pass initialValue to reduce(). See code below-

const numbers = [9, 8, 7, 6, 5, 4, 3, 2, 1];

const total = numbers.reduce((accumulator, currentElement) => accumulator+ currentElement, 5)
console.log(total)  //50

// OR
function calculate(accumulator, currentElement) {
  return accumulator + currentElement
}

const total = numbers.reduce(calculate, 5);
console.log(total)  //50

Array.prototype.reduce() can take two arguments, 2nd argument is optional which is initialValue for the accumulator.

  • if we pass the 2nd argument to .reduce() then the accumulator's initial value is set to the argument passed and the currentElement starts from the 1st element of the array, i.e 9.
  • if we don't pass the 2nd argument then the accumulator's value is initialized with the first value of array, i.e 9, and currentElement is set to 2nd value of the array., i.e 8.

Read more on MDN

forEach()

  • forEach takes a callback function and executes that function once for each array element.

Read more on MDN

Example

const numbers = [9, 8, 7, 6];

numbers.forEach((element, index) => {
    console.log('index: ' + index + ' number: ' + element)
})

//output
//index: 0 number: 9
//index: 1 number: 8
//index: 2 number: 7
//index: 3 number: 6

Summary

  • Function in javascript can be assigned to a variable, passed as an argument, or returned from another function.
  • Higher-order function takes another function as an argument or returns a function from it.
  • Javascript also has built-in Higher-order functions. map, filter, reducer and forEach are built-in higher-order functions.
ย