One of the features of JavaScript that makes it so convenient for functional programming is that it can accept higher-order functions. A higher order function is a function that can take another function as an argument or return another function as a result.
First class functions
You've probably heard that JavaScript refers to functions as objects of the first class. This expression merely means that in JavaScript functions have the same status as objects: they have the type Object; they can be set as a variable value; they can be passed and returned by reference like any other variables.
This native property gives javascript special features in functional programming. Since functions are objects, the language supports a natural approach to functional programming. In fact, this approach is so natural that I bet you probably used it and did not think about it.
')
We accept functions as arguments
If you have been doing a lot of web-oriented Javascript programming or browser development, you have probably come across functions that use the callback function (
callback - comment of the translator). A callback function is a function that is executed at the end of an operation when all other operations have been completed. Typically, the callback function is passed as the last argument to the function. Often, a callback function is defined as an anonymous function.
Since JavaScript is a single-threaded programming language, that is, operations are performed in turn, each operation is queued for admission to a single stream. The strategy of transferring a function for execution when the other parent functions are completed is one of the main characteristics of programming languages ​​that support higher order functions. So, you can get asynchronous behavior, that is, the script, waiting for the result, will continue to run. The ability to transfer callback functions is important when working with resources that can return a result after an indefinite period of time.
This approach is very convenient in a web development environment, where the script can send an Ajax request to the server, and then process the response regardless of the time it was received, taking into account network delays and server processing time. Node.js often refers to callback functions for the most efficient use of server capacity. This approach is also effective when applications are waiting for data input from the user before starting the function.
For example, look at the simple JavaScript code snippet below, which adds an event handler to the button:
<button id="clicker">So Clickable</button> <script> document.getElementById("clicker").addEventListener("click", function() { alert("you triggered " + this.id); }); </script>
This script uses an anonymous function to display a warning. However, he could as well 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);
Notice that we passed proveIt, and not proveIt () to our addEventListener function. When you pass a function by name without parentheses, you pass a function object. When you pass it with parentheses, the result of the function is transferred.
Our small proveIt () function is structurally independent of the code surrounding it, always returning the id of the element on which it worked. This small code can be in any context in which you want to display a warning with the element id and can also be called by any event handler.
The ability to replace a separately defined function with a named function opens up a whole world of possibilities. As we try to create pure functions that do not change external data and each time return the same data with the same input, we get an important tool that will help us create a library of small, objective functions suitable for use. in any application.
We return functions as results.
In addition to the ability to take functions as arguments, JavaScript allows functions to return other functions as a result. This is logical, since functions are just objects, and can be returned, like any other value.
But what does it mean to return a function as a result? If you set a function as the inverse of another function, you can create functions that can be used as templates for creating new functions. This opens the door to the world of functional magic in javascript.
For example, suppose that you are so tired of reading about the millenials feature that you decide to replace the word “millenials” with the phrase “snake people” every time it is found on the Web. Usually you would just write a function that you would like to replace one text with another:
var snakify = function(text) { return text.replace(/millenials/ig, "Snake People"); }; console.log(snakify("The Millenials are always up to something."));
This will work, but only in this particular situation. You are also tired of hearing about baby boomers. You want to write a custom function for them too. The only problem is that even for such a simple function you do not want to repeat the code already written:
var hippify = function(text) { return text.replace(/baby boomers/ig, "Aging Hippies"); }; console.log(hippify("The Baby Boomers just look the other way."));
However, what if you decide to do something more refined to save the algorithm in code? To do this, you will have to change both the first and second functions. This is very troublesome and makes the code more fragile and difficult to read.
What you really need is flexibility in the code in which you can replace a term with any other term in a function template, and determine the behavior of the main function from which you can create many others.
Using the ability to return functions instead of values, JavaScript allows you to accomplish the task much more efficiently:
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."));
We have separated the code that does the main work into a universal and expandable function that encapsulates all the work required to change any line using the original phrase, replacing it from a certain position.
Defining a new function as a reference to the attitude function that received the first two arguments allows the new function to accept any argument and use it as the source of the text in the internal function returned by the attitude function.
So, we use the ability of JavaScript functions not to depend on the initially specified number of arguments and accept any number of them. If the argument is missing, the function will simply treat it as unspecified.
On the other hand, this additional argument can be passed later, when the requested function is set as we described above, namely: as a reference to a function returned from another function with one or more unspecified arguments.
Go through the text again if you do not understand how higher order functions work. We create a function template that returns another function. Then, we set this just returned function, excluding one attribute, as custom implementation of the function template. All functions created in this way inherit the same code from the function template, but can by default take different arguments.
You are already using higher order functions.
Higher-order functions are at the very core of JavaScript, so you already use them. Every time you need to pass an anonymous function or a callback function, you work with the value that the function returns, and use it as an argument to another function.
The ability of functions to return other functions makes JavaScript extremely convenient and allows us to create custom functions to perform specific tasks with a commonly used function template. Each of these small functions receives all the improvements that appear in the code of the function template. This allows you to avoid duplicate code, as well as make the code more clean and readable.
As an added bonus: if you make sure that the functions have no side effect, so that they do not change the values, but always return them unchanged for any data entry, you have a great opportunity to create test suites and check that the changes in the template function code do not lead to errors.
Just think how you can use this approach in your own projects. The advantage of JavaScript is that you can add new functionality to the code that is already used. Try experimenting. You'd be surprised how a couple of simple manipulations with higher-order functions can improve your code.
about the author
M. David Green
I worked as a web developer, writer, communications manager and director of marketing for companies such as Apple, Salon.com, StumbleUpon and Moovweb. My study “Sociology in Telecommunications”, which I conduct at the University of California at Berkeley, as well as a master's degree in business on the topic “Organizational Behavior”, became sufficient grounds to understand that a person is driven by the instinct of communicating with his fellows, that this instinct is strong enough and It works always and everywhere, regardless of the medium of communication.
Worked on the translation:
greebn9k (Sergey Gribnyak),
silmarilion (Andrey Khakharev)
Singree