Higher Order Functions - A pragmatic approach
Tags: javascript, higherorderfunctiions, es6, pragmatic
Published: 2020-07-18 12:17:23

## Intoducting HoF
Its a common saying that functions are the bread and butter of programming, and the basic unit for building reusable logic in many programming languages, but **What makes a function become higher-order?** 
In simple terms, a HoF is just a kind of function that can accept other function(s) as argument or/and return a function. 
Still Not clear? ,Its fine, 
> a line of code says more than a thousand words. Lets proceed.

There are many different scenarios for approaching HoF but i would list some of the mot common as we continue

### Filtering Collections
To demonstrate a simple example, we consider a basic attempt to get only even numbers from a collection, we do the following:
```javascript
const nums = [1, 2, 3, 6, 8, 11];
const result = [];

for(let i=0; i < nums.length; i++) {
     if(nums[i] % 2 == 0) {
         result.push(i)
     }
     return result;
 }

result     // [2, 6, 8]
```
This approach seems to work, but if the criteria for selecting the result become a little complicated, things can easily start to look messy, also leaving no room for reusability. A better approach would be to write a custom filtering logic as we do below.

```javascript
function filter(nums, test) {
      let result = [];
      for(let i=0; i<nums.length; i++) {
          if(test(nums[i])) {
              result.push(nums[i])
          }
      }
      return result;
  }
```
The function we have just written would expect a collection as its first argument and another function as its second argument, which would be used to perform the selection criteria, now we can easily demonstrate the previous example again.
```javascript
 let result = filter(nums, num => num % 2 == 0);
 result;      // [2, 6, 8]
```
It should noted that the custom filter function defined above is only a naive attempt to implement the more robust and efficient inbuilt `Array.prototype.filter` built-in method, for filtering Array collections.

### Grouping 
An even more useful application for HoF would be to group collection by say some arbitrary tag, and presenting them in a nicer arrangement.
This is one in many scenarios where higher order function begins to shine. Lets implement the logic to group items

```javascript
function group(items, groupBy) {
        let grouped = Object.create(null);

        for(let i=0; i < items.length; i++) {
            let tag = groupBy(items[i])
            if(tag in grouped) {
                grouped[tag].push(items[i])
                continue;
            }
            grouped[tag] = [items[i]];
            
        }

        return grouped;
    }
```
For this example we would utilize the group function we just defined to re-arrange a collection, using a arbitrary tag.
```javascript
const items = [
     {tag: "car", name: "tesla", model: "Y"},
     {tag: "smartphone", name: "Samsung", yr: "2019"},
     {tag: "car", name: "mercedes", model: "classic"},
     {tag: "gaming", name: "PS5"},
     {tag: "smartphone", name: "Iphone", yr: "2019"}
]
const tagged = group(items, item => item["tag"]);

tagged   
/*
  {
     car: [
        { tag: 'car', name: 'tesla',model: "Y"},
        { tag: 'car', name: 'mercedes', model: "classic" }
     ],
     smartphone: [
        { tag:'smartphone', name: 'Samsung s9', yr: "2018" },
        { tag:'smartphone', name: 'Iphone 11', yr: "2019" }
     ],
     gaming: [ { tag: 'gaming', name: 'PS5' } ]
    }
*/
```
Cool right? :blush: With HoF we can easily express this logic and still maintaining readability of our code.

### Flattening Arrays
Ill leave you with this attempt to flatten a nested array, of an arbitrary depth. The first attempt would make use of the built-in Array.prototype.reduce. Lets do that.

```javascript
function flatten(nested) {
    return nested.reduce((flat, next) => {
        return Array.isArray(next) ? [...flat, ...next]
                                   : [...flat, next]
    }, [])
}

const nest = [1, 2, [3, 5], 0]
const deeper = [1, 2, [3, 5, [0, 9, 1]], 0]

flatten(deep)   // [1, 2, 3, 5, 0]
flatten(deeper)   // [1, 2, 3, 5, [0, 9, 1], 0]
```
Notice that trying to flatten a deeply nested array, seemed not to yield the expected output :frowning:. However, we can do better, and we try a second approach but this time using the good old recursion technique in combination with `Array.prototype.reduce`

```javascript
function flatten(nested) {
    return nested.reduce((flat, next) => {

        if(Array.isArray(next)) {
            return [...flat, ...flatten(next)]
        }

        return [...flat, next]

    }, [])
};

flatten(deeper)  // [1, 2, 3, 5, 0, 9, 1, 0]
```
Viola, we get the result we expected. It works!!!  :satisfied:

### Conclusion

In essence higher order functions are not really difficult to understand, although they could look somewhat intimidating at first. Many popular javascript libraries including Redux, use them behind the scenes to expose simple interface for implementing even very complex logic.

I hope you do enjoy this article, as much as i did putting it up. Please leave your review below.

Say hi on [twitter](https://twitter.com/nuel_ikwuoma)  :blue_heart:
Lovely weekend to you!