I am not sure I understand the value of the functional style looping/mapping if we can't use the break and continue keywords.
I can do this:
collections.users.models.forEach(function(item, index) {
//can't use break or continue...?
});
or I can do this:
for (var i = 0; i < collections.users.models.length; i++) {
if (user.username === collections.users.models[i].username) {
app.currentUser = collections.users.models[i];
break;
}
}
what's the advantage of the functional call if I can't use the break or continue keywords?
You can't natively break from
forEach
oreach
callback function. However, there is a technique many people use to break from this with customized exception:Simple approach above is creating a
BreakException
object and raise it whenever you want to break from the unbreakable loop. Catch that particularBreakException
and carry on what your function does.One thing to remember, always check if the caught exception is BreakException as you defined, since the other possible exceptions (like TypeError, etc) also got trapped by this catch statement. Don't swallow it without checking.
Using
Array.prototype.some
andArray.prototype.every
to continue/break out of functional for loops is a good thing to doeach
expresses your intent: to iterate and perform a side effect for each item.each
abstracts the process of iterating: initializing and incrementing a counter, fetching by array index. That's what the functional combinators do.Your code snippet is a great example. Let's rewrite that in a functional style:
find
clearly expresses your intent and abstracts the concept of iterating until you find an item matching your predicate..each()
or.forEach()
are less flexible than a plainfor
loop. They just are.As you have discovered, they offer you less control over the looping. They are a convenience ONLY when you want to iterate the entire set or when it really helps you to automatically have a new function context for your loop iteration code (sometimes useful in async operations) or when you enjoy the more declarative coding in that using the method expresses your coding intent a little more clearly and succinctly than the
for
loop..forEach()
will also automatically skip sparse elements of an array.Other than those features, they are just a reduction in typing that sacrifices some looping control. Use them when you like one of the advantages and don't use it when you need more looping control.
FYI, for Javascript arrays,
.some()
and.every()
attempt to get you back some looping control, though they are still not as flexible as afor
loop.If you use
.some()
, you canreturn true;
to be the equivalent ofbreak;
(since that will stop the looping) and you can justreturn;
to be the equivalent ofcontinue;
(since that will return from the callback and advance to the next iteration).To be honest, there is not much of an "advantage" so much as a convenience. You can call
return
to force yourself out of a single iteration of aforEach
loop, but this is not the same as the nativefor
because you are still invoking a function. The convenience comes in the form of not having to define the parameterization of your loop (ie. start point, end point, step size) as well as providing the value of the index and item in the items iterated over.It is worth mentioning that this convenience comes at the cost of for loop control (ie. start point, end point, step size), backwards iteration, the ability to
break
the entire loop, a small performance impedance, and yes, even cross browser compliance.