Higher-Order Functions In JavaScript
Tags: javascript, beginners, programming, webdev
Published: 2023-01-30 18:23:58

One of the sweet things I really enjoy about JavaScript is the fact that it is a multi-paradigm programming language, you can 
apply different paradigms of programming; object-oriented, functional, event-driven, etc
Although most times, we tend to treat JavaScript as a functional programming language based on our preference, one of the things
When dealing with JavaScript as a functional programming language, we need to note that we cannot be mutating states or change values assigned to variables.
A way we can achieve this is by using higher-order functions.

Before we begin to talk about higher-order functions in JavaScript let's understand some basic concepts about JavaScript that
will make reading this article easy to follow.  Concepts like:

- declaring functions in JavaScript 
- function arguments in JavaScript  
- function return type
- functions in JavaScript as a first-class citizen

And later in this article, we will be touching:
-higher-order functions in JavaScript
-examples of higher-order functions in JavaScript
- use cases of high-order functions in solving problems in JavaScript
- writing your own higher-order functions in JavaScript
- Let's also play around with writing some built-in higher-order functions in JavaScript.

Let's dive in,

Declaring Functions in JavaScript:

Declaring functions in JavaScript is simply done by giving a function name, a function body, and a return value(if required)

```
function firstFunction
{
console.log("our first function")
}
//So when we want to make use of the function :

firstFunction()
```
We just wrote a basic function, let's continue:
Let's write a function that can sum up two numbers; we will need two arguments, parameters are used when a function is declared but arguments are used when the function is called

```
// Definition:
function sumTwoNumbers(num1,num2)
{
  const sum = num1 + num2
   return sum
}

//Let's call the function:
//Here we will pass the parameters which are in this case the two //numbers we want to add together
console.log(sumTwoNumbers(3,7)
// The result we have is 10

```
And the result will always be consistent and correct as long as nothing goes wrong in the function block

In the function we just wrote to sum up two numbers, we are actually returning the sum of the two numbers.. One thing we need to take note of is that
whenever we have a return statement in a function, the function stops executing at that point, we will make use of this later.. 

Functions in JavaScript can be treated as first-class citizens, what I am saying here is that functions can be treated as a variable in JavaScript, let me explain this
using the previous functions we have written.

```
//The first function we wrote can be written as :
const firstFunction = ()=>{
console.log("our first function")
}
```
You notice we are declaring our function as a variable here, let's also re-write the second function

```
const sumTwoNumbers = (num1,num2) => num1 + num2

```

This looks shorter right? Let me explain what is happening here, instead of writing long lines of code, if you want to write a function that does not require 
multiple lines of logic, you also notice we don't explicitly write a return statement but as far as there is no curly brace after the big fat arrow, the function
returns the value of _num1 + num2
_


We can now safely move on to higher-order functions in JavaScript:

Higher-order functions are functions that take a function as an argument and or or return a function

There are various higher-order functions in JavaScript, we will only be touching a few of them.

**setTimeOut**:
**setTimeOut** takes in an anonymous function as its first parameter and the time in milliseconds as the second parameter.

Let's say we want to print out the current date and time after 4 seconds of running the snippet:

```
setTimeout(()=>{
    console.log(new Date)
},4000)
```

**Array.map()** :
a map function is used to map through an array, but unlike the regular _forEach_ or for, map function returns an array

For Example, let's say we want to add two to every number in an array of numbers

If we want to do this with our regular _forEach_, we will do it this way:

```
const numArr = [1,2,3,4,5,6,7,8,9,10]
const newNumArr = []

numArr.forEach((num)=>{
    newNumArr.push(num + 2)
})

console.log(newNumArr)
```

We get the result we want but, remember if we are doing functional programming at its core, we wouldn't want to be mutating state..
This is now where we can make use of a higher-order function:

```
const numArr = [1,2,3,4,5,6,7,8,9,10]
const newNumArr = numArr.map(num => num + 2)
console.log(newNumArr)
```


Apart from that the code is more readable and precise, you should also notice that we do not have reason to reassign or mutate any variable..
That's one of the reasons we use higher-order function


**Array.reduce()**

Let's say we want to want to add all the numbers in an array of numbers, using our _forEach_ loop, we would write something like this:


```
const numArr = [1,2,3,4,5,6,7,8,9,10]
let accumulatedSum = 0

numArr.forEach(num => {
    accumulatedSum += num

}    
)
console.log(accumulatedSum)
```

Though _forEach_ is still a higher-order function but remember we want to avoid mutating states..

We can use the **reduce()** function to achieve what we want :

```
const numArr = [1,2,3,4,5,6,7,8,9,10]

const arrSum = numArr.reduce((accumulator,currentValue)=> accumulator + currentValue,0)

console.log(arrSum)
```

In case you have not used the reduce function before, let me explain; 

The _reduce()_ method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

The first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise, the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0).


_callbackFunction_
A function to execute for each element in the array. Its return value becomes the value of the accumulator parameter on the next invocation of _callbackFunction_. For the last invocation, the return value becomes the return value of reduce().

The function is called with the following arguments:

_accumulator_
The value resulting from the previous call to _callbackFunction_. On the first call, _initialValue_ if specified, otherwise the value of array[0].

_currentValue_
The value of the current element. On the first call, the value of array[0] if an _initialValue_ was specified, otherwise the value of array[1].

_currentIndex_
The index position of _currentValue_ in the array. On the first call, 0 if _initialValue_ was specified, otherwise 1.

array
The array _reduce()_ was called upon.

_initialValue_ Optional
A value to which _accumulator_ is initialized the first time the callback is called. If _initialValue_ is specified, _callbackFunction_ starts executing with the first value in the array as _currentValue_. If _initialValue_ is not specified, _accumulator_ is initialized to the first value in the array, and _callbackFunctiion_ starts executing with the second value in the array as _currentValue_. In this case, if the array is empty (so that there's no first value to return as _accumulator_), an error is thrown.

So the complete syntax for reduce is 

```
Array.reduce((accumulator,currentValue,currentIndex)=>{

// write your reducer logic here

},initialValue)
```

We can perform a few more complex tasks using _reduce()_:

Let's say we have an array containing the objects of the student's name, age, and state of origin and we want to have a method that we can use to group the student list 
by any of the three fields(**name**, **age** or **state of origin**)

```
const students = [
    { name: "Mike", age: 10,stateOfOrigin:"Niger" },
    { name: "Max", age: 12,stateOfOrigin:"Oyo" },
    { name: "Jane", age: 15,stateOfOrigin:"Abia" },
    { name: "Adora", age: 13,stateOfOrigin:"Benue" },
    { name: "Aishat", age: 14, stateOfOrigin: "Rivers" },
    { name: "Abu", age: 15,stateOfOrigin:"Adamawa" },
    { name: "Abraham", age: 14,stateOfOrigin:"Adamawa" },
    { name: "Tunmise", age: 15,stateOfOrigin:"Oyo" },
  ];

  const groupBy = (studentData,groupByProperty) => {
    return studentData.reduce((accumulated,currentObj)=>{
        const key = currentObj[groupByProperty]
        const currentGroup = accumulated[key] ?? []

        return {...accumulated,[key]:[...currentGroup,currentObj]}
    },{})
  }

  const groupedStudentByState = groupBy(students,"stateOfOrigin")

  console.log(groupedStudentByState)
```

In the snippet above, we have an array of student data and we also have a function to group the data we have.

In the groupBy function, we are returning the grouped data directly, the function takes in two arguments; the studentData and the groupByProperty, We are using a 
reduce() function on the studentData; following the syntax for reduce(), we have a callback function that takes in  accumulated data, the current value as parameters,
we also have the initial value which is an empty object { }.



Making your own higher-order function in JavaScript
Let's say you are working on a project with different folders,for example, express js and you have the models, controllers, routes, etc folders
When you write a function and you want to track if an error occurred or not when the function is called, you can pass in a _callBack_  into the function.

For Example

```
// models/

const insertDataToDB = (...args,callBackFn) =>
{
  db.query(...,[],(err,res)=>{
    if(err){
    callBackFn(err,null)    
}
if(res){
   callBackFn(null,res)
}

})
}

export {insertDataToDB}

// controller/
import {insertDataToDB} from "../models/..."

const insertData = (req,res)=>{
   insertDataToDB(req.body,(error,data)=>{
    if(error){
    res.status(500).json({...error})    
}

if(data){
res.status(200).json({...data})
}

})
}

```
In the insertToDB function, we passed in a callBack into the function so when we call the function in the controller, we can check if an error occured or not and we can respond to the request.

I really hope you have learned a lot through this article, check up some of the code snippets in this article on [GitHub](https://github.com/oluwatobiisaiah/higher-order-fn-blog) do well to like and share this post and also follow me on Twitter and LinkedIn to get more updates from me, thank you see you soon.


 [Linkedln](https://www.linkedin.com/in/adedeji-oluwatobi-67b419237)
[Twitter](https://twitter.com/Adedeji46055573?t=l_tkfF1YmXoh_9Mv7I5UVQ&s=09)