Higher-Order Functions in JavaScript: A Practical Guide

Functions that take another function as an argument, or that define a function as a return value, are called higher-order functions.

JavaScript can accept higher-order functions. This ability to handle higher-order functions, among other features, makes JavaScript one of the most suitable programming languages ​​for functional programming.

Javascript treats functions as first class citizens

You may have heard that JavaScript functions are first class citizens. This means that functions in JavaScript are objects.

they have type ObjectThey can be assigned as a value to a variable, and they can be passed and returned just like any other reference variable.

First-class functions give JavaScript special powers and enable us to benefit from higher-order functions.

Because functions are objects, JavaScript is one of the popular programming languages ​​that supports a naturalistic approach to functional programming.

In fact, first-class functions are so core to JavaScript’s approach that I’m sure you’re using them without even thinking about it.

Higher-order functions can act as an argument

If you’ve done a lot of JavaScript web development, you’ve probably come across functions that use callbacks.

A callback function is a function that executes at the end of an operation, once all other operations have completed.

Normally, we pass this function as the last argument after other parameters. It is often defined inline as an anonymous function. Callback functions rely on JavaScript’s ability to handle higher-order functions.

JavaScript is a single-threaded language. This means that only one operation can be executed at a time.

To avoid operations that block each other or the system’s main thread (which causes deadlocks), the engine ensures that all operations are executed in sequence. They are queued with this single thread until it is safe for another transaction of code.

The ability to pass a function as an argument and run it after the original function’s other operations have completed is essential for the language to support higher-order functions.

Callback functions in JavaScript allow asynchronous behavior, so a script can continue to perform other tasks or operations while waiting for the result.

The ability to pass a callback function that can return a result after an undefined period of time is important when working with resources.

This higher-order function pattern is very useful in web development. A script can send a request to the server, and then handle the response whenever the response arrives, without requiring any knowledge of the server’s network latency or processing time.

Node.js often uses callback functions to make efficient use of server resources. This asynchronous approach is also useful in the case of an app that waits for user input before performing a function.

Example: Passing the alert function to the Elementor event listener

Consider this snippet of simple JavaScript that adds an event listener to a button.

So Clickable

document.getElementById("clicker").addEventListener("click", function() 
alert("you triggered " + this.id);
);

This script uses an anonymous inline function to display the alert.

But it could easily have used a separately defined function and passed that named function addEventListener method:

var proveIt = function() 
alert("you triggered " + this.id);
;

document.getElementById("clicker").addEventListener("click", proveIt);

We haven’t just performed higher-order functions by doing this. We’ve made our code more readable and flexible, and have different functionality (listening for clicks vs alerting the user) for different tasks.

How higher-order functions support code reusability

our little proveIt() The function is structurally independent of the code surrounding it, always returning id Whatever element was triggered. This approach to function design is at the core of functional programming.

This bit of code can be present in any context where you display an alert with id of an element, and can be called with any event listener.

The ability to replace an inline function with a separately defined and named function opens up a world of possibilities.

In functional programming, we try to develop pure functions that do not change external data and return the same result each time for the same input.

We now have one of the tools needed to help us develop a library of small, targeted higher-order functions that you can use in general in any application.

Note: passing a function vs passing a function object

Note that we have passed proveIt no more proveIt() For us addEventListener Celebration.

When you pass a function name without parentheses, you are passing the function object itself.

When you pass it with parentheses, you are passing the result of executing that function.

Returning function as result with higher-order functions

In addition to taking functions as arguments, JavaScript allows functions to return other functions as a result.

This makes sense because functions are just objects. Objects (including functions) can be defined as the returned value of a function, such as strings, arrays, or other values.

But what does it mean to return a function as a result?

Functions are a powerful way to break down problems and create reusable pieces of code. When we define a function as the return value of a higher-order function, it can serve as a template for new functions!

It opens the door to another world of functional JavaScript magic.

Let’s say you’ve read more than one article about millennial And got tired. you decide you want to replace the word millennial with phrase snake people Happens every time.

Your impulse might just be to write a function that performs that text replacement on whatever text you pass in:

var snakify = function(text) 
return text.replace(/millenials/ig, "Snake People");
;
console.log(snakify("The Millenials are always up to something."));

It works, but it’s pretty typical for this one situation. Perhaps your patience has even outweighed the articles about baby boomers, You might want to create a custom function for them as well.

But even with such a simple function, you don’t want to repeat the code you’ve written when you can start with a higher-order function instead.

var hippify = function(text) 
return text.replace(/baby boomers/ig, "Aging Hippies");
;
console.log(hippify("The Baby Boomers just look the other way."));

But what if you decided you wanted to do something fancier to preserve case in the original string? You will have to modify both of your new functions to do this.

It’s a hassle, and it makes your code more brittle and harder to read. In situations like this, we can use a higher-order function as a solution.

Creating a Template Higher-Order Function

What you really want is the flexibility to be able to replace any term in a template function with another term, and define that behavior as a basic function from which you can create new custom functions.

Along with the ability to assign a function as a return value, JavaScript provides ways to make that scenario more convenient:

var attitude = function(original, replacement, source) 
return function(source) 
return source.replace(original, replacement);
;
;

var snakify = attitude(/millenials/ig, "Snake People");
var hippify = attitude(/baby boomers/ig, "Aging Hippies");

console.log(snakify("The Millenials are always up to something."));

console.log(hippify("The Baby Boomers just look the other way."));

What we’ve done is separate the code that does the actual work into a versatile and extensible attitude Celebration. It encapsulates all the operations needed to modify any input string using the original phrase as the starting value, and outputs the replacement phrase with some approach.

What do we get when we define this new function as a reference? attitude Higher-order function, pre-populated with first two arguments? This allows the new function to take any text you pass in and use that argument in the return function we defined attitude output of the function.

Javascript functions don’t care about the number of arguments you pass to them.

If the second argument is missing, it will consider it undefined. And this will happen even if we choose not to provide a third argument, or even any additional arguments.

Also, you can pass that extra argument later. You can do this when you have defined the higher-order function you want to call, as just shown.

Simply define it as a reference to a function. A higher-order function with one or more arguments leaves undefined.

Watch it a few times if needed, so you fully understand what’s going on.

We are creating a template higher-order function that returns another function. Then we are defining an attribute of that newly returned function, minus one, as a custom implementation of the template function.

All functions you create in this way will inherit working code from higher-order functions. However, you can predefine them with different default arguments.

You are already using higher-order functions

Higher-order functions are so basic to the way JavaScript works, you’re already using them.

Every time you pass an anonymous or callback function, you are actually taking the value that the passed function returns, and using it as an argument to another function (such as with an arrow function) .

Developers become familiar with higher-order functions in the process of learning JavaScript. It is so intrinsic to the design of JavaScript that the need to know about the concept driving arrow functions or callbacks may not arise until later.

The ability to assign functions that return other functions enhances the convenience of JavaScript. Higher-order functions allow us to create custom-named functions to perform special tasks with shared template code from first-order functions.

Each of these functions can supersede any improvements made to a higher-order function down the road. It helps us avoid code duplication, and keeps our source code clean and readable.

If you make sure that your functions are pure (they don’t change external values ​​and always return the same value for any input), you can create tests to verify that when you do your first-order your code changes don’t break anything.

conclusion

Now that you know how a higher-order function works, you can start thinking about ways you can take advantage of the concept in your projects.

One of the great things about JavaScript is that you can mix functional techniques with code you’re already familiar with.

Try some experiments. Even if you start out by using a higher-order function for this, you’ll soon become familiar with the additional flexibility they provide.

A little work now with higher-order functions can improve your code for years to come.

Leave a Reply