How can I break (similar to the break
statement) from an implicit loop on an array?
The Array.prototype.map
, Array.prototype.forEach
, etc. functions imply a loop over the elements of the array. I want to conditionally break that loop early.
This contrived example:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.map(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
break;
}
});
causes a SyntaxError: unlabeled break must be inside loop or switch
.
How can I break the loop the same way a break
statement would?
Array#map
, Array#forEach
and so on have never been designed to be stopped. That would feel odd since the intent of map
as well forEach
really is to iterate over all items.
Also i don't think it is possible to notify the caller that a break
event has occurred, since it is within a function that is not an integral part of the original loop.
So let's see at a custom method that stops the loop at the first occurrence of true
without returning the matching value itself:
Object.defineProperty(Array.prototype, 'untilTrue', {
enumerable: false,
value: function(lambda) {
for(let i in this) {
if(lambda.call(this, this[i])) return;
}
}
});
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.untilTrue(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
console.log(item);
});
Comparing this custom untilTrue
to the use of Array#find
:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
colours.find(item => {
if (item.startsWith("y")) {
console.log("The yessiest colour!");
return true;
}
return false;
});
The only notable difference is that untilTrue
doesn't return the matching item - Array#find
does that in addition to call lambda
.
So in general i would just stick to Array#find
to keep the code neat and clean and use it like this:
const colours = ["red", "orange", "yellow", "green", "blue", "violet"];
if(colours.find(item => item.startsWith("y")) !== undefined) {
console.log("The yessiest colour!");
}
This stops the loop at the first match (and returns the matching element). Also note that you have to compare against undefined
- in case you were searching for a false
or null
value, the check would never evaluate to true
if just compared to true
.