2

I'm learning about Promise in Javascript and I can't figure out why these are the same:

let fifteen = Promise.resolve(15);
fifteen.then(value => console.log(value));

vs.

let fifteen = Promise.resolve(15);
fifteen.then(console.log);

Any pointer would be appreciated.

trincot
  • 317,000
  • 35
  • 244
  • 286
hubpixel
  • 319
  • 1
  • 10
  • 1
    If the function you want to call doesn't use `this`, or is bound, they are the same. However, when passed directly, unbound functions lose their `this` context when called. For `console.log`, it should work the same both ways. – FZs Dec 18 '20 at 06:41
  • 4
    This is unrelated to promises. It has to do with passing a callback. The principle is the same with, for example, `array.forEach`, or with `setTimeout` or your own function that can receive a callback. – trincot Dec 18 '20 at 06:44
  • @trincot Thanks, I need to get back to basic on callback here, why are the following have the same output? function test(callback) { callback("test-output"); } test(console.log); vs. test((value) => console.log(value)); – hubpixel Dec 18 '20 at 22:12
  • I added an answer where I address this. – trincot Dec 18 '20 at 22:30

2 Answers2

1

This pattern is unrelated to promises. It has to do with passing a callback. The principle is the same with, for example, array.forEach, or with setTimeout or your own function that can receive a callback.

So for example, if you define such a function yourself, it could be (like you mentioned in comments):

function test(callback) { 
   callback("test-output"); 
} 

If you want to print "test-output", you would call test like in this short version:

test(console.log); 

You could also call it like in this longer version:

test((value) => console.log(value));

The long version

In the latter case you actually create an anonymous (arrow) function on-the-fly:

(value) => console.log(value)

This is a wrapper around console.log. If you call it with some argument, you end up calling console.log with that same argument. You have in some way created a synonym for console.log because to the outside world it behaves in the same way. You could do something more elaborate, and define that function in a non-anonymous way:

function wrapper(value) { 
    console.log(value)
}

And then use that -- now named -- function at the place where we had the anonymous function:

test(wrapper);

We didn't change much: we just moved the function to another spot, turned it into a non-arrow function (not really needed), and gave it a name (wrapper). So the name wrapper is now synonym for that function. And so passing that to test is just the same thing as passing the literal function definition itself.

This makes very clear now that we just added a tiny, extra layer on top of the final call to console.log: first we call test, then test will call wrapper, and finally wrapper will call console.log.

The short version

The first, shorter way of calling test, is not beating around the bush: it just says: "the function I want you to call is console.log". And so test calls it:

callback("test-output"); 

It provides the argument "test-output". Do realise that the callback variable is a reference to console.log now, since that is the argument we passed to test. Both console.log and callback now reference the same function. So callback("test-output") is just the same as console.log("test-output").

So here we have one level less than in the longer version. The sequence is that we call test, and then test calls console.log. The wrapper thingie is not there.

NB: There are some things to say about this binding here, which does not have any bearing on the example above, but if that topic concerns/interests you, then read more about it in: How does the this keyword work in JavaScript.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thanks. Your explanation make sense, I now understand the first case: "callback("test-output") is just the same as console.log("test-output")" However, for the second case, I'm still a little confuse on the concept of wrapper around another function as in (value) => console.log(value). Is there another example/resource that you can point me to specific to this wrapper concept? – hubpixel Dec 18 '20 at 22:48
  • I extended my answer a bit, I hope it clarifies the wrapper concept. – trincot Dec 18 '20 at 22:57
0

The difference of

  • .then(console.log)
  • .then((value)=>console.log(value))
    is just in the first case, console.log implicitly receive the result, but in the second case explicitly receive the result. So the result is same.
  • hyojoon
    • 493
    • 1
    • 6
    • 17
    • Thanks, So given a function, we will need to read the source code to find out if a function would implicitly receive the result? I'm still unclear, if you can provide an example code showing under what condition a function can receive an implicit return, that would be great. – hubpixel Dec 18 '20 at 07:11
    • @hubpixel I think this [link](https://www.codeproject.com/Tips/1221966/JavaScript-Functions-Implicit-Parameters) can be helpful (about arguments obejct) – hyojoon Dec 18 '20 at 07:29
    • Thanks for the article. So in the case of .then(console.log) , where is the argument passed to the console.log? I understand about the explicit part, but still confuse about the implicit. – hubpixel Dec 18 '20 at 08:13