5

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).
Simone
  • 20,302
  • 14
  • 79
  • 103
root44
  • 75
  • 4
  • `noisy` accepts a function and returns a function which calls the passed function. – pishpish Apr 24 '18 at 14:12
  • I assume the purpose of `noisy` is to make some (well...) noise upon invoking the function (`f`) that is being passed to it. So, after you call `noisy(Math.min)` you get back a function that is then invoked using the `(3,2,1)` parameters. Essentially, decorating (or "proxying") the call to `f` for the purpose of logging to console before and after the actual invocation of `f`. – haim770 Apr 24 '18 at 14:12
  • 1
    Possible duplicate of [What is 'Currying'?](https://stackoverflow.com/questions/36314/what-is-currying) – Etheryte Apr 24 '18 at 14:13

3 Answers3

2

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.

Simone
  • 20,302
  • 14
  • 79
  • 103
  • Ok I get it. It could have been written like this (noisy(Math.min))(3,2,1) The precedence of the () operator causes it to be executed like I have written? – root44 Apr 24 '18 at 14:36
  • Yes, correct, but it won't work if written like in your second example, because they're not equivalent. `noisy(Math.min(3,2,1))` is a regular function call where `Math.min(3,2,1)` is the first and only argument. – Simone Apr 24 '18 at 14:43
  • Yes I understand that now. Thanks. – root44 Apr 24 '18 at 16:04
  • Thanks so much for posting this. I had the exact same question! – adm-gis Oct 22 '20 at 14:05
0

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, i.e:

let result = f(...args);

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

Kristianmitk
  • 4,528
  • 5
  • 26
  • 46
0

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));
Emil S. Jørgensen
  • 6,216
  • 1
  • 15
  • 28