Question

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
  1. 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)
    
  2. What is happening in this line? Where is f() even defined?

    var val = f(arg);
    
Was it helpful?

Solution

  1. 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.)

  2. 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.

OTHER TIPS

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;
}

I'm relatively new to JS and I've also just been reading through Eloquent Javascript and I found it easier to understand once I understood the calling of the function (answering your point 1):

noisy(Boolean)(0);

The noisy(Boolean) creates a new function and the (0) is after it because it is being passed as an argument into that new function. If you refer back to the greater than example:

function greaterThan(n) {
  return function(m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));

It could also be called in this way:

greaterThan(10)(11);

I hope that clarifies your first question about why it was called that way.

For the second question. The f in:

var val = f(arg);

is the Boolean function that was passed into noisy when noisy(Boolean) was entered. It was then used as the argument in the noisy function. I also didn't realise that Boolean could be a function in itself and not just a data type. As others have said - it converts the argument you gave it into a Boolean value and returns the result.

Therefore val becomes Boolean(arg) which becomes Boolean(0) which evaluates to false. If you try call noisy(Boolean)(1);you will see it return true. The console.log("called with", arg, "- got", val); simply logs the argument (0 in this case) and the result of evaluating it (false).

In effect, it has changed the Boolean function into one that logs the argument and result, as well as returning the result.

I hope this helps. Just writing it has helped my own understanding.

Javascript variables do not have a static datatype. They can be assigned variables of different datatypes also.

There is no concept of typecasting in JS like in JAVA etc.

() in a function call corresponds to the invoking of the function.

Here, Boolean seems to be a higher order function which is passed as a parameter to the noisy function. The result of the noisy function will be

function(arg) {
  console.log("calling with", arg);
  var val = f(arg);
  console.log("called with", arg, "- got", val);
  return val;
};

The second parantheses with 0 is used to invoke this result.

Here, within the above function, note the below line.

var val = f(arg);

Here, f corresponds to the Boolean function which was passed earlier. arg corresponds to 0.

Since val is returned, the result of the expression will be the result of Booelan(0).

In case you're still having trouble with this, here's how I understand it (it gave me a headache too..)

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)

A function is just a regular value. The previous sentence is key to understanding what's going on here.

Our noisy(f) function is a value. It is what it returns.

noisy(f) returns a function which takes an argument (arg).

noisy(f) also takes an argument (f). Inner functions (functions called from within functions) have access to variables and arguments which were passed to the outer function.

We're calling our outer function and passing it the argument Boolean. Our outer function returns its inner function which takes an argument (0). By understanding the above it should become clear that noisy(Boolean(0)) would simply pass an argument to our outer function, while not passing anything to the inner function which is returned by our outer function.

It's so simple really. Now that we understand it, it's hard to believe it gave us such a headache to begin with... */`

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top