# Higher-Order Functions in JavaScript

One of the pros of JavaScript that makes it well-suited for functional programming is the fact that it can accept higher-order functions. These are functions that can:

- Accept other functions as arguments
- Returns a function as a result.

To fully understand this concept, you first have to understand what Functional Programming is and the concept of First-Class Functions.

## Functional Programming

 It's a form of programming in which we can pass functions as parameters to other functions and also return them as values. In functional programming, we think and code in terms of functions.

JavaScript treats functions as first-class citizens. What this means is that functions in JavaScript are treated as objects. They have the type `Object`, they can be assigned as the value of a variable, and they can be passed and returned just like any other reference variable.

This ability gives JavaScript special powers when it comes to functional programming. Because functions are objects, the language supports a very natural approach to functional programming.


## Functions as arguments

#### example 1

```
function greet() {
  console.log("Good Morining");
}

function greetMe (func) {
    func();
}

greetMe(greet); // Good Morning
```

As we can see in the above example, we declared a `greet` function or `callback` function then passed it as an argument in the `greetMe` function. Note that we must specify that the `greetMe` function should accept an argument.

#### example 2
This time let's write a function with a callback function that will be called `n` times,

```
function hello () {
    console.log('Hello');
}

function sayHello ( action, num ) {
    for ( let i = 0; i < num; i++ )
    {
        action();
    }
}

sayHello( hello, 5 ); // Hello Hello Hello Hello Hello
```
In the above example, we declared a `hello` function then passed it as an argument in the `sayHello` function which receives a second argument that will determine the number of times we will call our `hello` function, we loop through whatever number was passed in and for each loop we return the `hello` function. So the `sayHello` function executed our `action` 5 times.

## Functions as return values

Now let's talk about returning a function from within a function. It's a little bit trickier to explain but you can kind of think of these functions as function factories. The function itself returns another function and in the example, I'll show you the functions on the outside, the outer functions are making new versions of a function, they're tweaking a function and returning it so we can reuse it as much as we want, so let's start with a simple example.


#### example 1

```
function greetMe () {
    return function ( ) {
        console.log('Hello');
    }
}

const greet = greetMe()

greet(); // Hello
```
We declared a `greetMe` function to return an anonymous function saying "Hello", we declare a variable greet to hold our `greetMe` function. Now, what do you think will be the value of `greet`?. Yeah, it will point to whatever the return value of our the greet me function is.

#### example 2 

```
function multiplyBy ( num ) {
    return function (x) {
        console.log(x * num);
    }
}

const triple = multiplyBy( 3 );
const double = multiplyBy(2)

triple( 3 ); // 9
double(5); // 10
```
Here the `triple` function expression holds whatever the return value of `multiplyBy` is which accepts whatever value we want to multiply our `triple` argument with same with `double`. The `multiplyBy` factory just gave us different functions.

JavaScript in itself has some built-in Higher-Order Functions like:
`filter()`
`map()`
`reduce()`
`sort()`
you can take a look at them and find how to utilize them.

## Conclusion

We have learned what Higher-order functions are and how to create them.

In summary, a Higher-order function is a function that may receive a function as an argument and can even return a function. Higher-order functions are just like regular functions with an added ability to receive and return other functions as arguments and output.





