cft

Advanced Concepts in Javascript — Higher Order Functions(HOF)

The art of making our code more general and avoid repeating ourselves


user

Allan Sendagi

3 years ago | 8 min read

Let's start off by reviewing our knowledge of functions.

We know that functions in Javascript are objects.
We also said that when we invoke a function, we get two parameters automatically:
 this keyword and arguments keyword.

source: ZTM Academy

We saw that arguments is an array-like object with weird behaviors for looping and iteration, so we want to avoid using it. Instead, we can use something like the spread operator.

We also learned that because of the arguments, we can have a function with no parameters defined but we can call it with parameters and still grab them using the arguments keyword.

We saw that when we define our functions, the compiler looks at our code lexically and determines what variables are available for us in our variable environment and also adds scope chains.

Function invocation

We saw a few ways of invoking functions.

  1. The first method we are very familiar with.

2. The second way we saw is as a method. A method is a function inside of an object.

We can simplify this function with the new ECMA script.

Notice that here obj is calling two(), the this keyword is updated to obj instead of window.

3. The third way to use functions is to use call.

4. Those are the three main ways but there is one more way you won't see very often.

This is called a function constructor.

Our built-in objects that the Javascript language comes with create functions for us. Here the first parameter is whatever we want the function task to be — which is to return 4.

But we can also have parameters.

I still get four.
Whatever is in the last parameter of the function will be the actual code body.

Functions are objects.

This is something not very common in other languages. In Javascript, I can do something like this:

We’ve added a property to a function

Underneath the hood what Javascript does is it creates a special type of object called a Callable Object. Something like this:

The callable object can be invoked

This code, of course, wouldn't work. It’s pseudocode to show you what's going on underneath the hood.

To summarise, if we had a function someFunc(), it would be an object with 3 special properties:

1. 
code(): It would have a piece of code that we can invoke with the two brackets. When we invoke with these brackets, it reads whatever the piece of code is in those brackets and executes it.

2. Name(optional): If for example the function was called someFunc, the name would be someFunc. But remember we also have anonymous functions.
If we used function expression, assign it to a
 var but the function itself is anonymous, well, the name wouldn't exist because it's optional.

3. Properties: We get properties automatically on a function. We have properties like call()apply() and bind() that allow us to operate upon that function.

For example, if I go back to woohoo,

We have the call() method available to us.

We also have properties like arguments, lengthname.

Objects

With objects, I don’t have the same properties and methods that we have seen such as call(), bind()apply() or any of the properties.

Remember functions are objects — but they are a special type of object. A callable object with a bracket notation for invoking a function, contains code, it has name and it also has some properties like call, apply and bind.

Why is this important?

Since functions are just objects in Javascript, we can pass them around like objects, or things that contain data.

So besides just doing things for us, and performing actions on our code, we can also store them as data, move them around and have some really interesting applications.

First-class citizen

Since functions can be passed around like data, besides just performing actions on our code, you will hear people say that functions are a first-class citizen in Javascript.

This means three things:

  1. Functions can be assigned to variables and properties of objects.
    So that I can do:

var stuff = function(){};

In some languages, I can’t do that. I can just run functions to perform actions and that's it. In Javascript, I can assign it to a variable or an object property which then becomes a method.

2. We can also pass functions as arguments into a function. So I can do:

Here we are able to pass a function as a parameter to a function.

3. We can return functions as values from other functions. What does that mean?

Or I can assign it to a variable and then just call that var d.

So those are the three properties that make functions a first-class citizen in Javascript. We are able to assign these functions to variables, we can pass these functions into arguments and we can also return functions as values from other functions.

So functions are data because not only do they perform actions for us but they can be passed around as if they were Javascript types. So anything you can do with other types, you can do with a function.

This idea of a first-class property introduces Javascript to a whole world called functional programming.

Things to avoid while using functions

  1. Avoid initializing functions inside loops.

Here every time we loop, for example when i=0, we are going to initialize the function a, and then run it. Same when i=1, we will initialize function a and then invoke the function and so on.

Instead of initializing the function inside of a loop, we should be moving the function up top. So that we initialize the function just once. When we loop over it, we are just executing it five times instead of initializing it and executing it.

2. Here another thing we should be careful of:

My function gives me a reference error because param is neither in the local or global scope.

As soon as we have nothing in our variable environment or scope chain, we get a reference error.
Now, this normally causes a lot of functions to fail and involves us always doing some sort of a check to see if the 
param exists.

We could, of course, add a param

So that if I run this I won't get that error. In this case, the param is added automatically to our variable environment as if we just declared that variable.

But when we call it with nothing, we just get undefined. One way to avoid this is if you just give it a default parameter which came with Es6.

Now if I run this, instead of undefined I get 6. So its good to have default parameters set as a way to avoid these edge cases.

Higher-Order Functions

HOF are functions that can take a function as an argument or a function that returns another function.

Why should we care about HOF?

First, let's look at the problems we can solve with just a function.

Suppose we have a company system that lets our users log in.

useless code to demonstrate authentication

With this function, there is a lag — it takes time to grant access to adam. And if we add another zero, things will be very slow.

Now, remember we are assuming that this is an authentication service that our company has. But what if we have more employees we want to authenticate.

Let's say we have Eva.
We will have to create another authentication function for Eva.

But now we have a problem with this code; Don’t we? We aren’t keeping our code DRY. We are repeating ourselves. The code we have created is not flexible.

For each user that we have, we have to copy and paste code and repeat ourselves. Just imagine if we had hundreds and hundreds of employees, doing this every time would not be inefficient.

So how can we fix this?

Let's move on from a single function to a function that accepts parameters.

So instead of having letAdamLogin letEvaLogin functions, lets create a generic function letUserLogin.

I will get access granted to Adam.

And for Eva:

I will get access granted to Eva.

Now, let's refactor the code to make it cleaner by creating another function giveAccess.

So I can just return giveAccessTo.

We have leveled up here. Now we tell the function what data to use when we call it.

Remember before our function whenever we called it decided what to do with that data. Instead, we now have a more generic function that says hey I am going to give you some generic piece of data I don't know what yet but when I pass you the user do some sort of functionality to it.

So that instead of defining Eva or Adam inside of a function, we can just define that later on when we just invoke the function

So we have the ability to define the data when we call the function. We have a little bit of flexibility. We kept our code DRY.

But what are the limitations here?

What if instead of just users we also have admin — Somebody with a lot more privilege?

Then we would have to copy the code

Now you have noticed here that since its admin, we have to go through a bit more procedures hence the “5000000” — let's say it takes a bit more time for them to get authenticated.

So the function has changed a little bit — we have a different permission process. But still, we just copied more code. We are not being very DRY.
And imagine if we had to give access to managers, secretaries, guest access and so on.

So what can we do here?

This is where higher-order functions can come into play.

Remember we went from simple functions function() to functions with parameters function(a,b). This meant that instead of just defining the function and telling it exactly what to do and what data to use, we are able to define what the function does but later on, when we call the function, we tell it what data we need.

With a higher-order function, we get to do both of those things when we call the function. We can give the function data but also tell it what to do or some extra abilities when we actually invoke it.

So how would this work?

First, let's create an authenticate function that takes a parameter — in our case a number which is the time of authentication. This is the verification process.

We have verified everything, you can have access — return true

We have the authenticate and giveAccess functions. Now how can we make the rest of the functions better?

Let's remove let the letUserLogin and letAdminLogin functions and instead let's create a general function letPerson.

So how did this make things easier?

Now we can do:

It works.
And if I change to admin:

That also works.

So what power did we just gain here?

Now we have the power to not only tell it what power to use, but also what to do.

We created a generic function letPerson compared to the previous letAdamLogin. It was too specific. letPerson accepts the person as the first parameter and then a function, in this case, authenticate as a second parameter.

So by making things general, we can now add something like a sing function:

Our letPerson function is more general now — it’s a higher-order function because it accepts a function as a parameter, I can now add many more functions:

We removed giveAccessTo function and added it to the authenticate and we just returned some generic functions in letPerson to have this work.

What we have been able to achieve with higher-order functions is this ability to tell a function what to do during invocation; we are able to have more flexibility than we had before and we avoid repeating ourselves.

Let's have one last example. Let's create a generic multiply function so that I am able to create multiple functions from it.

With this in place, I can now store my function in another variable let's say:

Now I have this functionality that I can keep reusing where I can:

2*4=8

2*10=20

I can have this functionality over and over with this higher-order function.

Here the multiplyBy is a higher-order function because it returns another function.

I can also extend this where I can do

6*5=30

We can also use arrow functions to write this in a much cleaner way.

Arrow functions visually make sense.

All its saying is:
Give me a parameter then another parameter. So if I just do:

4*6=24

And that's all these brackets are showing you and by now I hope we can see the power of HOF.

We learned how to go from a simple function() to a function with parameters function(a,b) to higher-order functions.The main benefit is we are able to make our code more general — DRY, we don’t repeat ourselves and we have the ability to break things down into more functionalities.

Upvote


user
Created by

Allan Sendagi

Technology will save homo sapiens from extinction


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles