简体   繁体   中英

Eloquent JavaScript, 2nd Edition, Chapter 5 Higher-Order Functions

I'm very new to JavaScript, and I was hoping to get some help with Chapter 5 in the 2nd Ed. of Eloquent JavaScript. Specifically, I ran into the example below:

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

I think I understand the concept of higher-order functions producing other functions, but I'm not sure I understand the idea of "capturing" and how it pertains here. Specifically, the line with var val = f(arg); .

Can someone please walk me through that line of code? How do you pass an argument to another argument? I'm not sure if I'm using the correct terminology, so please excuse me if I've got it wrong. I just don't understand that line and couldn't easily find any other threads about this subject.

Thanks!

noisy is a function that takes a reference to another function f and returns a new function that wraps f so that it's call and return values are logged to the console.

val is the result of the function f being called, where f is a function reference that is passed when noisy is called.

To go step by step:

// noisy accepts argument f (where f itself appears to be a function)
function noisy(f) {
    // noisy returns a new function that takes an argument arg
    return function(arg) {
        // when this new function is called, it logs to console
        console.log("calling with", arg);
        // the function you originally passed to noisy is now called, with the return value stored in val
        var val = f(arg);
        // return value val also logged to console
        console.log("called with", arg, "- got", val);
        // return value val is returned from the generated function
        return val;
    };
}
// noisy is called with the inbuilt function Boolean and the argument 0 (to test the boolean value of 0)
noisy(Boolean)(0);

Another use case could be something like this:

function someFuncToMonitor(someArg) {
    return someArg + 1;
}
monitoredFunc = noisy(someFuncToMonitor);
result = monitoredFunc(5);
// calling with 5
// calling with 5 - got 6

So in short calling monitoredFunc calls your someFuncToMonitor function for you and tells you about the call and the results.

Code in question:

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

What happens (kind of like a "magic schoolbus" journey through JavaScript):

  1. Nothing is actually executed until the line of code noisy(Boolean)(0);
  2. When this line is reached, first the noisy function is called with the JavaScript built-in function Boolean as its argument f .
  3. An anonymous function is returned:
    • when run, the anonymous function receives a new argument called arg .
    • then the anonymous function will log the string "calling with" followed by the arg .
    • then the anonymous function will call the function f (which has been memoized within the anonymous function by closure) and store the return value in the variable val .
    • then the anonymous function will log the string "called with" followed by arg , followed by the string "- got", followed by val .
    • finally, the anonymous function will also return the value in the variable val .
  4. The return value of noisy(Boolean) is the anonymous function as described above, with Boolean playing the role of f within this anonymous function that was just generated.
  5. The remaining (0) is now used to call this newly generated anonymous function with an argument arg of 0.
  6. The five sub-steps described in 3. above are followed, resulting in:
    • no visible output, but arg takes on a value of 0 as the initial step of the anonymous function's invocation.
    • the anonymous function logs the string "calling with 0"
    • the Boolean function is run with an argument of 0, which returns false , which is stored into val .
    • the anonymous function logs the string "called with 0 - got false"
    • the anonymous function returns false (but this value is not used or stored in any way by the example code).

Now let's go through the actual lines of code and match them with the above steps:

  1. This code begins to be executed: noisy(Boolean)
  2. The following code within noisy is executed, with argument Boolean being passed into noisy and stored into the variable f :

     return function(arg) { console.log("calling with", arg); var val = f(arg); console.log("called with", arg, "- got", val); return val; }; 
  3. The noisy(Boolean) part of this code noisy(Boolean)(0); has now been replaced with the return value shown in step 2.
  4. So now the line noisy(Boolean)(0) has in effect become [[anonymous function]](0) .
  5. This replacement "code" [[anonymous function]](0) is now executed.
  6. As a result, the following lines of code are executed:

      console.log("calling with", 0); // because 0 was passed in for arg var val = Boolean(0); // because Boolean is stored in f console.log("called with", 0, "- got", false); // because the Boolean value of 0 is false 

The noisy function takes a single parameter f which is a function. When you call noisy, it returns a new function (which means noisy(Boolean) returns a function). The capturing takes place because the new function has access to any parameters of noisy, including the f parameter (programmers call this concept a closure). When you have noisy(Boolean)(1) the f inside the inner function is referring to Boolean . So, val gets set to Boolean(1) since var val = f(arg) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM