Higher Order Functions in Javascript

Photo by Andrew Neel on Unsplash

Higher Order Functions in Javascript

How to Use Higher Order Functions

Introduction

Javascript is a high-level multipurpose programming language used for web and mobile app development which has a syntax that is quite easy to understand but in most cases can be a little confusing since it can be written in different ways, so today we will look into different concept in javascript which can be confusing in most cases but can be broken down into simpler pieces.

What are Higher Order Functions?

A Higher Order function is a function that can do the following

  • Accept another function as an argument (callback functions) or

  • Return another function on its call (closures) or

  • Do both above

Let's look at the cases above and let us break them down

Accepting Function as an Argument

What this simply means is that when we have a function and give it a parameter the value of the parameter which can be a number, string, boolean, array or object is now a function. Let us look at an example which is a code for performing conversions

//higher function using function as an argument
function convert(number,conversionFunction){
  const value = conversionFunction(number);
  console.log(value);
}
//callback functions
function convertUSDToNaira(number){
  const rate = 450;
  return number * rate + " NGN";
}
function convertNairaToUSD(number){
   const rate = 450;
   return number/450 + " USD";
}

//function call
convert(100,converUSDToNaira); // logs 45000 NGN
convert(5000,converNairaToUSD); // logs 11.11 USD

so let's breakdown the code and see how it works;

Firstly we created a function called convert which has 2 parameters the first one which is number and the other called convertFunction as we can see in the convert function body we made a function call to the second parameter and gave it the value of the number parameter as an argument and we got the result from the function and logged it to the console. The reason we called the second parameter is to indicate that we need a function as an argument because we can only call functions and not booleans or numbers or strings.

Secondly, we created two different functions

  • convertUSDToNaira

  • convertNairaToUSD

which have two different functions and these functions are then provided to the main function as arguments to the main convert function which uses them in its function call. These functions are called callback Functions because they are used by another function and are supplied to another function as arguments

Now you might wonder do we necessarily need to do this? it depends on the case, but in our case, our function has expanded our basic function into a more dynamic use and made our function more flexible as we saw in the following function we made two separate functions that have different tasks but still work out with our main function which is considered our Higher Order Function.

We can also re-write the above code using an anonymous function

function convert(number,conversionFunction){
  const value = conversionFunction(number);
  console.log(value);
}
convert(500000,function(number){
   return number/500 + " USD"
})// logs 1000 USD

this code above does the same as the first code the only thing is the use of an anonymous function which is simply a function that does not have a name and is mostly used as a callback function

We can also write it using ES6 arrow functions

function convert(number,conversionFunction){
  const value = conversionFunction(number);
  console.log(value);
}
convert(500000,number=> number/500 + " USD") //logs 1000 USD

Return another function on its call (closures)

What this means is that a function returns another function from its call instead of a number, string, or array. Now when do we do this? we can basically do this when we need our functions to perform some operation that should follow a certain order which helps to organize our function, let us see an example that will help us understand this

function searchAndAdd(list,query){
   const newList = []
   for(const item of list){
      if(item.includes(query)){
         newList.push(item)
       }
   }
    return addToAnotherList(anotherList){
       return [...anotherList,...newList]
    }
}
const addToAnother = searchAndAdd(["James", "John", "Jane", "Peace"], "q")

const myList = addToAnother(["a","b"])

Let us break down the example and see how it works;

We create a function called searchAndAdd which has 2 parameters the list and query parameters which we use to perform a for loop to filter through the list and add the items that pass our test to the newList, after that we then return a function that takes the newList we created and the anotherList parameter we added to the returned function and returns the combination of the both. As we can see from the first function call we did the filtering which then returns a new function we then use to get a combined list.

We can see that in the above example, we used a higher-order function to execute things in a certain order which makes our code more organized, in most cases we don't really need to do this but we can see the essence of this kind of Higher Order Function

Do Both

Basically, if the function does any of the above we can call it a higher function, if it can also do both it is also considered a higher-order function which can bring a lot more flexibility and structure, let's rewrite the second case the use both callbacks and closures to improve its flexibility

function searchAndAdd(list,query,doSomething){
    const newList = doSomething(list,query)
    return addToAnotherList(anotherList){
       return [...anotherList,...newList]
    }
}
const addToAnother = searchAndAdd(
  ["James", "John", "Jane", "Peace"],
  "J",
  function(){
  const newList = []
   for(const item of list){
      if(item.includes(query)){
         newList.push(item)
       }
   }
   return newList
})


const myList = adToAnother(["a","b"])

Now the example is a bit confusing but let's also break it down, now we used a callback function instead of writing the functionality and separating the logic, this way we can actually change how the main function behaves based on whatever callback function we provide and allows us to do more dynamic functions while still giving us that processing order which we still need

Conclusion

As we can see higher-order functions are really good for implementing more flexibility and structure around functions and we should understand them even do we might not be creating our own, most of the time, other Javascript frameworks make use of this principle to create some core functionalities of their framework