I am reading Eloquent JavaScript (The new edition) and I reached the part on higher order functions and I'm confused on what's happening in the following code.
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0);
// → calling with 0
// → called with 0 - got false
Why is the call to the function noisy like this? Is (Boolean) a cast? A cast for what? the return value? or the argument? why not (Boolean)noisy(0) if its the return value. Or noisy((Boolean) 0) if the argument is the one being casted.
noisy(Boolean)(0)
What is happening in this line? Where is f() even defined?
var val = f(arg);
Boolean
is a function. It's the function you're calling indirectly through noisy
. A bit confusing, I know, because it looks like the name of a type. But in JavaScript, those initially-capped things (Boolean
, Number
, String
, and so on) are functions. When you call Boolean
(without using new
), it tries to convert the argument you gave it into a boolean
primitive value and returns the result. (See §15.6.1 in the spec.)
f
is the name of the argument in the noisy
function.
Functions in JavaScript are first-class objects. You can pass them into other functions as arguments just like any other object.
When you do
noisy(Boolean)(0)
There are two things going on. First:
// (In effect, we're not really creating a variable...)
var x = noisy(Boolean);
That gives us a function that, when called, will call Boolean
with the argument we give it while also doing those console.log
statements. This is the function you see being created in noisy
(return function(arg)...
);
Then we call that function:
x(0);
And that's when you see the console output. Since Boolean(0)
is false
, you see Boolean
return that value.
Here's a much simpler example:
function foo(bar) {
bar();
}
function testing() {
alert("testing got called");
}
foo(testing);
There, I'm passing the function testing
into foo
. The argument name I'm using for that within foo
is bar
. The line bar();
calls the function.
A function without the () is the actual function. A function with () is an invocation of the function. Also keep in mind that JavaScript is a loosely typed language, so you don't declare variable types. I've added some comments to your example to try and help.
// We define a function named noisy that takes in an argument named f. We are expecting f to be a function but this isn't enforced till the interpreter throws an error.
function noisy(f) {
// Noisy returns a single item, an anonymous function. That anonymous function takes in an argument named arg
return function(arg) {
console.log("calling with", arg);
// Our anonymous function then takes f (It can use f because its defined inside noisy, see closures for more details) and invokes it with the argument arg and stores the result in a variable named val.
var val = f(arg);
console.log("called with", arg, "- got", val);
// It now returns val
return val;
};
}
So then noisy(Boolean)(0) works like this
f is the function Boolean
noisy returns a function like this
function(arg) {
var val = Boolean(arg);
return val;
}
So now we have
our returned function(0)
which executes like normal to become
function(0) {
var val = Boolean(0); // false
return val;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With