简体   繁体   中英

Can someone explain this higher-order JavaScript function confusing syntax?

I am reading the book "Eloquent JavaScript".

In Chapter 5 he describes a particular higher-order function. It is called noisy() it is printed below...

function noisy(f) {
  return (...args) => {
   console.log("calling with", args);
   let result = f(...args);
   console.log("called with", args, ", returned", result);
   return result;
 };
}

Here is the part that is confusing me. He calls the function noisy as follows...

noisy(Math.min)(3,2,1);

I do not understand why the function is called that way. Why isn't it called like this...

noisy(Math.Min(3,2,1))

Edit: I see now what is going on. It was explained by Simone below.

noisy(Math.min)(3,2,1) is equivalent to (noisy(Math.min))(3,2,1).

If you try to get the type of noisy , you'll get:

typeof noisy
>> "function"

Same thing if you ask for the type of noisy(Math.min) :

typeof noisy(Math.min)
>> "function"

If you want you can also store this function into a variable:

const noisyFunction = noisy(Math.min)

So that you can call it like a regular function:

noisyFunction(1,2,3)

noisy(Math.min)(3,2,1) is exactly the same, just written in a different, shorter way. The main point is, a higher-order function is just a function that returns a function.

noisy takes a function as a parameter, and returns a function. The thing you pass it is expected to be a function. We can see that in this line here:

let result = f(...args);

f is the parameter. That line of code using it as a function.

noisy gives you a function back. We can see that here in the code:

return (...args) => {

The important thing is that a function is not the same as the value returned by a call to the function. Math.min is a function, a thing. Math.min(1, 2, 3) is a call to a function , an action -- which returns a number. When you put the parentheses on Math.min , that tells the compiler you want to execute Math.min .

Math.min(1, 2, 3) doesn't return a function, it returns a number. The code you were given isn't passing that parameter list to Math.min ; it's passing that parameter list to a completely different function, the one returned by noisy .

This becomes more clear if we assign the values to local variables:

//  x is a function, not a number. 
var x = Math.min;

//  y is a function: noisy returns a function.
var y = noisy(x);

//  Call the function noisy returned:
var z = y(1, 2, 3);

If we break down your version of the call, noisy(Math.Min(3,2,1)) , we get this:

//  Set x equal to the integer value 1
var x = Math.min(3, 2, 1);
var y = noisy(x);

Look inside noisy . It returns a function which includes the following line:

let result = f(...args);

So, in your version, y is the function that noisy returns. It's never executed, but if it were, it would be trying to treat the integer value 1 as a function. But an integer is not a function.

noisy(Math.min) returns a function (see the return statement: return (...args) => { ... } ).

noisy(Math.min)(3,2,1); just immediately calls that function.

You could also first assign the function to a variable and then call it like this:

let fnct = noisy(Math.min);
fnct(3,2,1);

You cannot call it like noisy(Math.Min(3,2,1)) as Math.min(3,2,1) returns a number but noisy expects a function reference to be passed (hence Math.min - note its missing the () as it's passing a reference to that function rather than the result of its execution).

Your call would break in line 4, ie:

let result = f(...args);

as f is not a function in your case but rather the result of Math.min(3,2,1) // = 1 .

noisy returns a function that uses the parameter f as a callback function.

Here is an es5 version of the code (which needs a little more code to maintain functionality) to help you understand:

 function noisy(f) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } console.log("calling with", args); var result = f.apply(void 0, args); console.log("called with", args, ", returned", result); return result; }; } //test console.log(noisy(Math.min)(3, 2, 1));

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