JavaScript Node.js Basics Building a Command Line Application Capturing Command Line Arguments

How does forEach pass the username to getProfile?

I got lost on this one when Andrew wrote:

users.forEach(getProfile);

I thought for sure we would have to write something like:

users.forEach(username => {
     getProfile(username);
});

How does getProfile get the username passed to it as an argument? Is this some new fancy ES2015 magic that it's smart enough to know to pass what forEach returns on each iteration to the get getProfile function as its argument?. I'm guessing it's either that, or something to do with closures.

2 Answers

Steven Parker
Steven Parker
174,085 Points

The "foreEach" method always passes 3 arguments to the function it calls: the current item, the item's index number, and the container itself. The function doesn't need to use all of these, or even any, but it's very common to use just the first one as in the example you have given.

This mechanism itself isn't really new, and is very much like how an event handler function is passed the event object.

Also, if you re-examine your examples you'll see that they both rely on the argument passed by "forEach". In the first it is received directly by getProfile, and in the second it is received by an anonymous function which then passes it along to getProfile.

"In the first it is received directly by getProfile"

That's what I wasn't expecting to be possible. I didn't know it was possible for getProfile to directly receive an argument from the forEach just by passing getProfile's function name only without passing it an argument in parens. I'm trying to understand how that works.

Steven Parker
Steven Parker
174,085 Points

That's not unique to forEach, that's just typical callback behavior. Remember that you only pass the function itself as a callback argument, either by name or by providing an anonymous function expression. But the code that uses that function is in control of how it is called, and what arguments it passes to it.

Yeah I get that it's not unique to forEach. But just to make sure I understand. If I were to use forEach as an example... are you saying that I could define a callback function that takes 3 arguments... then pass it by name only as the callback argument for forEach... and forEach would give my callback the currentValue, index, and array? Like this?

someArray.forEach(callback);

function callback(currentValue, index, array) {
     //do stuff
}

If so, clearly I need to go back and review how callbacks work... because I've always just passed an anonymous function.

Steven Parker
Steven Parker
174,085 Points

Yes, that's exactly right. And it doesnt matter if you pass a named function or an anonymous function expression. Either one will still get the same things passed to it, and can be written to accept one or more of them as arguments.

Adding to your example, you could also create the same callback as a function expression:

someArray.forEach((currentValue, index, array) => { /* do stuff */ });

And the function expression is how I've always done it. Either that way or with the old ES5 syntax. You've been a tremendous help. Thanks for taking the time to explain all that!

Michael Braga
Michael Braga
Full Stack JavaScript Techdegree Student 20,765 Points

We cant directly see (not that I know of) what is actually happening within the forEach method call. But the code would be something like this:

NOTE: This is just pseudo code to show that something similar is happening within the forEach call

function forEach(callback) {
  let array = this;
  for(let i = 0; i < array.length; i++) {
    callback(array[i], i, array);
  }
}

Once I understood this, iteration method calls (forEach, reduce, map) became very easy to understand. Hope this helps for anyone who is confused.