Higher Order Functions
Published: 2022-06-17 22:22:30

Higher Order functions takes in arguments as an argument or return a function. Using these allows your code to run more efficiently and reduces repetitiveness. The result is code that is easier to read and easier to de-bug. Whether you are using native methods (helper functions), using recursion, or writing your own callback functions, you will become a better programmer when you are utilizing these tools.
    


**Filter, Map, and Reduce**
The filter, map and reduce functions are three invaluable tools for dealing with collections of large amounts of data. The filter function takes in an array and a test function as arguments:

```
function filter(array, testFunc){
 let results = [];
for(let i = 0; i < array.length; i++){
  if (testFunc(array[i], i, array)) {
    results.push(array[i]);
  }
}
  return results; 
}
```
Invoking this function will return a new array, with only the values that satisfy the condition in the input function. Upon the function being called, the input array is iterated through; and for each element the input function is called on it, if true, it's pushed into the array. The function returns a new array without mutating the input array, thus it is a pure function.  

```
let numbers = [2, 3, 5, 18, 21, 22, 27, 33];
console.log(filter(numbers, function(number) {
  return (number % 3 === 0);
```
Here, invoking the filter function created above with an anonymous function tests each element of the numbers array to see if it is divisible by 3.  This function call would log to the console: [3, 18, 21, 27, 33]. Or the same could be done using the native filter method like this: 

```
let divByThree = function(array){
  let filtered = array.filter(function(element){
    if (element % 3 === 0){
      return element;
    }
   }
  return filtered; 
});
console.log(divByThree(numbers));
```

**The Native Methods**
Since the native methods exist, there is no need to create the function from scratch each time. The map function one that is used to iterate through a collection and returns a new array of identical length to the input array (or object) with each all elements change in a way that input function dictates.  For example, all the values inside of an array could be cubed with this function: 

```
let nums = [1, 2, 3, 4, 5];
let cubeEach = function(array){
  let mapped = array.map(function(element){
    return element ** 3; 
  })
return mapped; 
};
  console.log(cubeEach(nums));
```

When invoked, in the background each element of the input array goes into function, cubed and pushed into the output array. After the iterating is complete, a new array is returned and the value of cubeEach = [1, 8, 27, 64, 125].

Reduce is another native method that will take a collection and return one value. This function, typically takes in more arguments than filter and map, usually 3: an accumulator, which will be the value that is returned, the current element of the collection (as it's being looped through), and a seed that represents the value of the accumulator at the time that it is called. Suppose the sum of all value of an array are needed:

```
let values = [1, 3, 5, 7, 9];
let addAll = function(array){
  let reduced = array.reduce(function(accumulator, current){
    accumulator += current; 
    return accumulator;
  }, 0); 
  return reduced;
};
console.log(addAll(values));
```
Above, the seed is given after the function body. When the function is called the value of accumulator is 0, then at each iterations it increases and is return after the value of the last element is added. Note type of data for the seed here is a number, but depending on what you are trying to return it can be string, array, or object. 

**Recursion**
A callback function includes a function invocation in its body as a return statement. Including callback functions can preserve values after the function has run (more on closure in a bit). Recursive functions are functions that re-invoke them over and over with one argument slightly changing with each time it is called. Below, the function will return the sum of all positive numbers less than or equal to the inputted value:

```
function recursiveSum(x, sum = 0){
  //base: when x has a value of 1, return
  if(x === 1){
    return sum + x; 
  }
  if(x < 0){
    return "the number is not positive";
  }
  //recurse: add the value and re-invoke function 
  else {
    sum += x;
    return recursiveSum(x-1, sum); 
  }
}
  
```
Until the base condition is satisfied, the function re-invokes itself each time with the value of x decreasing each time.  The second argument is set at 0 for the first invocation but is changed each time in the body of the function. When recursiveSum(3) is called, it is re-invoked 2 more times until it hits the base condition, where 6(3 + 2 + 1) is returned. 

The examples given here have been fairly simple and straightforward, but these methods/techniques can be combined with others, scaled up and/or altered to handle complex data. As a beginner, getting comfortable with these can be a useful first step on your way to becoming a Javascript expert.