1

I'm trying to understand callbacks thoroughly and this is the fundamental missing piece. I've scoured the internet for this answer but most just talk about async callbacks.

Q 1: Why do some built-in methods like Array.prototype.forEach() use synchronous callbacks? What advantage does this feature provide?

Q 2: How do we decide it's time to use a synchronous callback when implementing custom methods of our own?

Background:

javascript's for of loop functionally does the exact same thing as its forEach() counterpart when talking about arrays. They both loop from the front to the end of the array. So why do we need both?

Two obvious differences (in general) I see are:

  1. for of loop can loop over any iterable, forEach is specific for arrays.
  2. for of loop allows us to use continue and break keywords, forEach() does not
  3. for of loop does NOT use a callback, forEach() DOES use a synchronous callback.

I see the importance of points 1 and 2, but I don't get point 3

Q: What advantage does forEach() provide by taking a synchronous callback as its argument?

An answer other than "it allows us to apply a function to each element" or allows us to "abstract away the logic" would be really helpful unless the answers are actually really just this obvious and I'm overthinking this.

Hope my question is unambiguous and super clear

enzo
  • 9,861
  • 3
  • 15
  • 38
jgrewal
  • 189
  • 1
  • 2
  • 11
  • 8
    The answers are actually really just this obvious and you're overthinking this. – VLAZ Aug 08 '21 at 22:09
  • forEach() is actually a fairly young method within the language history and was added on top of for loops mostly for convenience. Why keep both? Don't want to break code using the older approach – charlietfl Aug 08 '21 at 22:10
  • 1
    Based on your question, I think you're talking more about why certain syntax constructs (i.e. for loops) have functions you can seemingly replace them with? Mind that `for of` also has other benefits, e.g. `await` support. One is JS syntax, the other is just an Array method. – Kelvin Schoofs Aug 08 '21 at 22:10
  • 6
    Don't look at `forEach`. Look at `map`, `filter`, `some` and the like. It's not about "having an advantage" - the whole method wouldn't be possible conceptually without callbacks! – Bergi Aug 08 '21 at 22:13
  • for of and forEach do *not* do the same exact thing – Dexygen Aug 08 '21 at 22:27
  • @Bergi yes, other methods won't be conceptually possible, so they make sense. But forEach() confused me, so I got stuck on that and thus the question. Thank you for clarifying nonetheless!! – jgrewal Aug 08 '21 at 22:31
  • @Dexygen Could you please elaborate? What am I missing? I know: 1) `for of` can be used on all iterables, whereas `forEach` is only for arrays 2) you can break out of `for of` or skip a step unlike `forEach` 3) as @Kelvin Schoofs just reminded me (thank you Kelvin!!), `for of` has await support `forEach` doesn't ... anything else I'm missing? – jgrewal Aug 08 '21 at 22:36
  • @JagnoorGrewal `forEach` also would not be possible conceptually - the usage of callbacks is really the same. Sure, you can (and [imo even should](https://stackoverflow.com/a/49420944/1048572)) avoid the usage of `forEach` because there are (nowadays) better alternatives, but that has nothing to do with the question why `forEach` uses a callback. – Bergi Aug 08 '21 at 22:39
  • @VLAZ lol. Funny answer – jgrewal Aug 08 '21 at 22:39
  • 1
    @JagnoorGrewal VLAZ's comment might be tongue-in-cheek, but it's true - you *are* overthinking this. You've already stated the purpose of `forEach` in your question. There's nothing behind it. – Bergi Aug 08 '21 at 22:42

1 Answers1

3

Callbacks aren't inherently synchronous or asynchronous. A callback is just a function that was given as an argument to another function.

When that callback gets called, is up to function and typically some other event precedes that. If that event is itself asynchronous, then the call is also asynchronous.

This is completely separate from forEach and a for. The reason both exists, is probably a combination of the following:

  • for(.. of ..) wasn't a thing for a long time, and for(.. in ..) has some surprising behavior related to prototypes. This led to many libraries implementing a functional (for)each, most notably jQuery.
  • Another jQuery-era reason why people liked jQuery each, is because lots of folks got confused around how variables behaved in scope/closures and loops. Doing a functional version makes it much easier to not have closure variables overwritten for previous iterations.
  • Lastly, some people just like the idea using functions for loops.

Especially the first two reasons made $.each popular, to a point where a native forEach was added to the language.

There's fewer reasons to use forEach today, because:

  • forEach doesn't work with await.
  • We now have block-scoped let and const so variables overwriting after each iteration of the loop is no longer an issue.
  • for(... of ..) does what people expects (no need for hasOwnProperty).
  • You can't 'break' with forEach

Some people still opt to using forEach if the above bullets aren't a concern. I don't fully understand that, but you can't really argue style.

Evert
  • 93,428
  • 18
  • 118
  • 189