Passing Functions Around
In the arrow functions lesson, const triple = n => n * 3 stored a function in a variable. That shows something important. In JavaScript, a function is a value, just like a number or a string. You can store it in a variable, and you can pass it to another function.
Here is a function that receives another function as its first argument:
function applyTwice(fn, x) {
return fn(fn(x));
}
const double = n => n * 2;
const exclaim = s => s + "!";
console.log(applyTwice(double, 5));
console.log(applyTwice(exclaim, "wow"));
Output:
20
wow!!
applyTwice does not know what fn does. It only knows that fn is a function, so it calls it. Pass double, and you get math. Pass exclaim, and you get punctuation. The same code does different work, and the caller decides which. A function that takes another function as an argument is called a higher-order function. A function that you pass in, so that it can be called later, is called a callback.
Look closely at what was passed: double, not double(5). The name alone passes the function itself. With parentheses, you call the function and pass its result. If you pass double(5) by mistake, fn holds the number 10, and calling it fails:
function applyTwice(fn, x) {
return fn(fn(x));
}
const double = n => n * 2;
console.log(applyTwice(double(5), 3));
Output:
/box/index.js:2
return fn(fn(x));
^
TypeError: fn is not a function
at applyTwice (/box/index.js:2:13)
at Object.<anonymous> (/box/index.js:6:13)
The message fn is not a function means: you tried to call something that is not a function. When you see it, check whether you passed a function or the result of calling one.
Why does this idea matter so much? A lot of JavaScript code works by saying "when this happens, run this function": when a button is clicked, when a timer ends, when data arrives. Each time, you hand a function to some other code, and that code calls it at the right moment. You will use this pattern with lists in the Array Methods section, and with time in the Async section.
In the exercise, complete applyTwice and use it with two different functions.