Using break and continue in each () and forEach ()
I'm not sure I understand the meaning of the functional style loop / match if we cannot use the break and continue keywords.
I can do it:
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 benefit of a function call if I can't use the break or continue keywords?
source to share
.each()
or .forEach()
less flexible than a simple loop for
. They just are.
As you have found, they offer you less control over your cycle. They are only handy when you want to iterate over the entire set, or when it really helps you automatically create a new function context for your iterative loop code (sometimes useful in asynchronous operations), or when you like more declarative coding in what a method expresses your the intent of the coding is a little more clear and concise than the loop for
. .forEach()
also automatically skips sparse array elements.
Aside from these features, it is just a typing reduction that sacrifices some loop control. Use them when you like one of the benefits, and don't use them when you need more loop control.
FYI, for Javascript arrays, .some()
and .every()
will try to give you some looping control back, although they are still not as flexible as a loop for
.
If you use .some()
, you can return true;
be equivalent break;
(since this will stop the loop) and you can just return;
be equivalent continue;
(since this will return from the callback and move on to the next iteration).
source to share
To be honest, there are not so many "advantages" as convenience. You can call return
to force yourself to exit one iteration of the loop forEach
, but this is not the same as native for
because you are still calling the function. The convenience comes in the form of not having to parameterize your loop (i.e. start point, end point, step size), and provide the index and element value in the elements that are renamed.
It's worth mentioning that this convenience comes with the cost for contour control (i.e. start point, end point, step size), reverse iteration, break
whole loop capability , low performance impedance, and yes, even browser compatibility.
source to share
each
expresses your intent: iteration and side-effect execution for each element. each
abstracts the iteration process: initialization and incrementing the counter, fetching by array index. This is what functional combinators do.
Your code snippet is a great example. Rewrite this in a functional style:
app.currentUser = collections.users.models.find(function (u) {
return u.username === user.username;
});
find
clearly expresses your intent and abstracts the concept of iteration until you find an element that matches your predicate.
source to share
You cannot naturally disconnect from the callback function forEach
or each
. However, there is a technology that many people use to opt out of this with a custom exception:
var BreakException = function(){};
try{
list.forEach(function(el){
if (meetCriteria(el)){
throw BreakException; // Break from forEach
}
});
}
catch (e){
// Catch break
if (e != BreakException)
throw e; // If not a break, but other exceptions, raise it
}
// Carry on
The simple approach above creates an object BreakException
and lifts it up when you want to break out of the unbreakable loop. Catch this quirk BreakException
and continue with what your function is doing.
Remember, always check to see if a BreakException is thrown as you defined, as other possible exceptions (like TypeError, etc.) are also caught in this catch statement. Do not swallow it without checking.
source to share