A function that takes another function as an argument, 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, along with 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, in JavaScript functions are objects.
They are of type Object
, they can be assigned as the value of a variable, and they can be passed and returned like any other reference variable.
First-class functions give JavaScript special capabilities that allow 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 you're using functions.
Higher-order functions receive functions as arguments
If you've done a lot of JavaScript development, you've probably encountered the use of callback functions.
A callback function is a function that is executed at the end of an operation and is executed once all other operations have completed.
Normally, we pass this function as the last argument, after other arguments. 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 performed at a time.
To avoid the main thread of an operation or system blocking each other (which would lead to a deadlock), the engine ensures that all operations are performed in order. They are queued along this single thread until it is safe to generate another code transaction.
The ability to pass in a function as an argument, and have that function run after the other operations of the parent function have completed, is crucial for languages that support higher-order functions.
Callback functions in JavaScript allow for asynchronous behavior, so the script can continue executing other functions or operations while waiting for a result.
The ability to pass callback functions is critical when dealing with resources that may return results after an indeterminate 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 as it arrives, without knowing 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 functions.
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 easy to use a separately defined function and pass this named function to the addEventListener
method.
var proveIt = function() {
alert("you triggered " + this.id);
};
document.getElementById("clicker").addEventListener("click", proveIt);
We do more than just show higher-order functions. We made the code more readable, more resilient, 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, always returning id
of the element that was triggered. This approach to functional design is at the heart of functional programming.
This code can exist in the context of any element you use with id
display 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 every time for the same input.
Now we have a basic tool that can help us develop a small, targeted library of higher-order functions that you can use in any application.
Note that we passed proveIt
instead of proveIt()
to our addEventListener
function.
- When you pass the name of a function without parentheses, you are passing the function object itself.
- When you pass a function in parentheses, you are passing the result of executing the function.
return function
In addition to taking functions as arguments, JavaScript 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, like strings, arrays, or other values.
But what does it mean for a function to return as a result?
Functions are a powerful way to decompose 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 a new function.
If you read too much about "Millennials" and get bored. You decide that whenever the word "millennials" comes up, you're going to replace it with the phrase "snake people."
You could simply write a function that performs that text replacement on whatever 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 notation is valid, but not general enough. You might 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 to do something more complicated to preserve 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 brittle and harder to read. In such cases, we can use higher-order functions as a solution.
Higher-order function templates
What you really want is the flexibility to be able to replace any term in a template function with any other term, and define that behavior as a base function from which you can build new custom functions.
With the ability to specify a function as the return value, JavaScript provides a convenient way to make this situation easier:
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 did was isolate the code that did the actual work into a common, extensible attitude
function. It encapsulates all the work required to modify any input string: use the original phrase as an initial value, and output a replacement phrase with a certain attitude.
What do we get when we define this new function as a reference to a higher-order function attitude
and prefill the first two arguments it receives? It allows the new function to take whatever text you pass it and use that parameter in the return function we defined as the output of the attitude
function.
JavaScript functions don't care about the number of arguments passed to them.
If the second parameter is missing, the function will treat it as undefined
. It also does so when we choose not to provide the third parameter, or any number of extra parameters.
Also, 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 to return another function. We then define this newly returned function, minus one attribute, as a custom implementation of the template function.
All functions you create this way will inherit the working code of higher-order functions. However, you can predefine them with different default parameters.
Higher order functions are being used
Higher-order functions are fundamental to the way JavaScript works, and you're already using 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 (like an arrow function).
Developers are familiar with higher-order functions early in their learning of JavaScript. It's inherent in JavaScript design, so you need to learn the concept of driving arrow functions or callbacks 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 with shared template code for first-order functions.
Each of these functions can inherit any improvements in higher-order functions. This helps us avoid code duplication and keeps our source code clean and readable.
If you make sure your functions are pure (they don't change external values, and always return the same value for any given input), you can create tests to 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 out just to use higher-order functions, you'll quickly become familiar with the extra flexibility they provide.
A little work using higher-order functions now can improve your code for years to come.
The above is the whole content of this article, thank you for reading~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。