How to use higher-order functions in JavaScript

A function that takes another function as a parameter, or defines a function as a return value, is called a higher-order function.

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

JavaScript treats functions as first-class citizens

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

Their types are such Objectthat they can be assigned as the value of a variable, and they can be passed and returned like other reference variables.

First-class functions give JavaScript special capabilities, allowing us to benefit from higher-order functions.

Since functions are objects and JavaScript is one of the popular programming languages, it supports a native approach to functional programming.

In fact, first-class functions are native JavaScript methods. I bet you’re using them without even thinking about the functions you’re using.

Higher-order functions receive functions as parameters

If you’ve done a lot of JavaScript development, you’ve probably come across the use of callback functions.

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

Normally, we pass this function as the last parameter, after the other parameters. It is usually defined as an inline 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 will be executed at a time.

To avoid operations or the system’s main thread blocking each other (which would lead to deadlock), the engine ensures that all operations are executed in order. They are queued along this single thread until it is safe to spawn another code transaction.

The ability to pass a function as an argument and run it after other operations in the parent function have completed is crucial for languages ​​that support higher-order functions.

Callback functions in JavaScript allow asynchronous behavior, so the script can continue executing other functions or operations while waiting for results.

The ability to pass a callback function is crucial when dealing with resources that may return results after an undetermined period of time.

This higher-order function pattern is very useful in web development. A script can send a request to the server and then need to process the response when it comes, without needing to know the server’s network latency or processing time.

Node.js often uses callback functions to efficiently utilize server resources. This asynchronous approach is also useful for applications that wait for user input before executing a function.

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

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

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

But it’s also just as easy to use a separately defined function and pass this named function to addEventListenerthe method.

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

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

We do more than just demonstrate higher-order functions. We made the code more readable, more flexible, and separated functionality for different tasks (listening for click events vs. alerting the user).

code reusability

Our proveIt()function is structurally independent of the code around it and always returns the element it was triggered on id. This approach to functional design is at the heart of functional programming.

This code can exist in any context where you use the element’s iddisplay alert, and can be called by any event listener.

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

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

Now we have a basic tool that helps us develop a small, targeted library of higher-order functions that you can use in any application.

Note that we pass proveItinstead of proveIt()to our addEventListenerfunction.

  • When you pass the name of a function without parentheses, you are passing the function object itself.
  • When you pass a function using parentheses, you are passing the result of executing the function.

return function

In addition to taking functions as arguments, JavaScript also allows functions to return other functions as results.

This makes sense because functions are simple objects. Objects (including functions) can be defined as the return value of a function, just like a string, array, or other value.

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

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

So you’ve read so many articles about “millennials” that you’re tired of them. You decide that every time the word “millennial” comes up, you’re going to replace it with the phrase “snake people.”

You might simply write a function that performs this text replacement on any text you pass it.

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

This way of writing is effective, but not general enough. You may want to write a replacement function for other cases:

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

But what if you decide you want to do something more complicated to preserve the case in the original string? You will have to modify your two new functions to do this.

This is cumbersome and makes your code more fragile and harder to read. In such cases we can use higher order functions as a solution.

Higher-order function template

What you really want is the flexibility of being able to replace any term with any other term in a template function and define that behavior as a base function that you can build new custom functions on top of.

With the ability to specify a function as a return value, JavaScript provides ways to make this situation 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." ));
 // The Snake People are always up to something. 
console . log ( hippify ( "The Baby Boomers just look the other way." ));
     // The Aging Hippies just look the other way.

What we’ve done is isolated the code that does the actual work into a common, extensible attitudefunction. It encapsulates all the work required to modify any input string: use the original phrase as the initial value, and output a replacement phrase with some attitude.

What do we get when we define this new function as attitudea reference to a higher-order function and prefill the first two arguments it receives? It allows the new function to receive any text you pass to it and use that parameter as the output of the function in the return function we defined attitude.

JavaScript functions don’t care about the number of arguments passed to them.

If the second argument is missing, the function will treat it as undefined. It will also do this when we choose not to provide a third argument, or any number of additional arguments.

Additionally, you can pass in that extra parameter later. You can do this after defining the higher-order function you want to call, as just demonstrated.

We are creating a template higher-order function that returns another function. Then, we define this newly returned function as a custom implementation of the template function, except for one attribute.

All functions you create in this way will inherit the working code of the higher-order function. However, you can predefine them with different default parameters.

Using higher-order functions

Higher-order functions are fundamental to the way JavaScript works, and you already use them.

Whenever you pass an anonymous function or callback function, you are actually using the value returned by the passed function as an argument to another function (such as an arrow function).

Developers become familiar with higher-order functions early in their learning of JavaScript. It’s inherent in the design of JavaScript, so you don’t need to learn the concept of driving arrow functions or callbacks until later.

The ability to assign values ​​to functions that return other functions extends the convenience of JavaScript. Higher-order functions allow us to create custom named functions that perform specialized tasks using shared template code for first-order functions.

Each of these functions can inherit any improvements from the higher-order functions. This 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 given input), you can create tests that verify that when you update a first-order function, your code doesn’t change Will break anything.

Summarize

Now that you know how higher-order functions work, you can start thinking about how to leverage this concept in your own projects.

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

Even if you start using higher-order functions just for the sake of using them, you’ll quickly become familiar with the additional flexibility they provide.

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

The above is the entire content of this article, thank you for reading~