Short circuit Array.forEach like calling break - javascript

[1,2,3].forEach(function(el) {
if(el === 1) break;
});
How can I do this using the new forEach method in JavaScript? I've tried return;, return false; and break. break crashes and return does nothing but continue iteration.

There's no built-in ability to break in forEach. To interrupt execution you would have to throw an exception of some sort. eg.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript exceptions aren't terribly pretty. A traditional for loop might be more appropriate if you really need to break inside it.
Use Array#some
Instead, use Array#some:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
This works because some returns true as soon as any of the callbacks, executed in array order, return true, short-circuiting the execution of the rest.
some, its inverse every (which will stop on a return false), and forEach are all ECMAScript Fifth Edition methods which will need to be added to the Array.prototype on browsers where they're missing.
Use Array#every
[1, 2, 3].every(v => {
if (v > 2) {
return false // "break"
}
console.log(v);
return true // must return true if doesn't break
});

There is now an even better way to do this in ECMAScript2015 (aka ES6) using the new for of loop. For example, this code does not print the array elements after the number 5:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (const el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
From the docs:
Both for...in and for...of statements iterate over something. The main difference between them is in what they iterate over. The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.
Need the index in the iteration? You can use Array.entries():
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}

You can use every method:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
for old browser support use:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
more details here.

Quoting from the MDN documentation of Array.prototype.forEach():
There is no way to stop or break a forEach() loop other than
by throwing an exception. If you need such behaviour, the .forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a boolean return value, you can use every() or some() instead.
For your code (in the question), as suggested by #bobince, use Array.prototype.some() instead. It suits very well to your usecase.
Array.prototype.some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

Unfortunately in this case it will be much better if you don't use forEach.
Instead use a regular for loop and it will now work exactly as you would expect.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}

From your code example, it looks like Array.prototype.find is what you are looking for: Array.prototype.find() and Array.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2

Consider to use jquery's each method, since it allows to return false inside callback function:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash libraries also provides takeWhile method that can be chained with map/reduce/fold etc:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []

If you would like to use Dean Edward's suggestion and throw the StopIteration error to break out of the loop without having to catch the error, you can use the following the function (originally from here):
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
The above code will give you the ability to run code such as the following without having to do your own try-catch clauses:
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
One important thing to remember is that this will only update the Array.prototype.forEach function if it already exists. If it doesn't exist already, it will not modify the it.

Short answer: use for...break for this or change your code to avoid breaking of forEach. Do not use .some() or .every() to emulate for...break. Rewrite your code to avoid for...break loop, or use for...break. Every time you use these methods as for...break alternative God kills kitten.
Long answer:
.some() and .every() both return boolean value, .some() returns true if there any element for which passed function returns true, every returns false if there any element for which passed function returns false. This is what that functions mean. Using functions for what they doesn't mean is much worse then using tables for layout instead of CSS, because it frustrates everybody who reads your code.
Also, the only possible way to use these methods as for...break alternative is to make side-effects (change some vars outside of .some() callback function), and this is not much different from for...break.
So, using .some() or .every() as for...break loop alternative isn't free of side effects, this isn't much cleaner then for...break, this is frustrating, so this isn't better.
You can always rewrite your code so that there will be no need in for...break. You can filter array using .filter(), you can split array using .slice() and so on, then use .forEach() or .map() for that part of array.

As mentioned before, you can't break .forEach().
Here's a slightly more modern way of doing a foreach with ES6 Iterators. Allows you to get direct access to index/value when iterating.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Output:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Links
Array.prototype.entries()
Iterators and generators
Destructuring assignment

Another concept I came up with:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});

This is just something I came up with to solve the problem... I'm pretty sure it fixes the problem that the original asker had:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
And then you would call it by using:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Returning false inside the callback function will cause a break. Let me know if that doesn't actually work.

If you don't need to access your array after iteration you can bail out by setting the array's length to 0. If you do still need it after your iteration you could clone it using slice..
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Or with a clone:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Which is a far better solution then throwing random errors in your code.

Found this solution on another site. You can wrap the forEach in a try / catch scenario.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
More details here: http://dean.edwards.name/weblog/2006/07/enum/

This is a for loop, but maintains the object reference in the loop just like a forEach() but you can break out.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}

try with "find" :
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }

Yet another approach:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);

I use nullhack for that purpose, it tries to access property of null, which is an error:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//

Use the array.prototype.every function, which provide you the utility to break the looping. See example here Javascript documentation on Mozilla developer network

Agree with #bobince, upvoted.
Also, FYI:
Prototype.js has something for this purpose:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break will be catched and handled by Prototype.js internally, breaking the "each" cycle but not generating external errors.
See Prototype.JS API for details.
jQuery also has a way, just return false in the handler to break the loop early:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
See jQuery API for details.

If you want to keep your forEach syntax, this is a way to keep it efficient (although not as good as a regular for loop). Check immediately for a variable that knows if you want to break out of the loop.
This example uses a anonymous function for creating a function scope around the forEach which you need to store the done information.
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
My two cents.

If you need to break based on the value of elements that are already in your array as in your case (i.e. if break condition does not depend on run-time variable that may change after array is assigned its element values) you could also use combination of slice() and indexOf() as follows.
If you need to break when forEach reaches 'Apple' you can use
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
As stated in W3Schools.com the slice() method returns the selected elements in an array, as a new array object. The original array will not be changed.
See it in JSFiddle
Hope it helps someone.

Why don't you try wrapping the function in a Promise?
The only reason I bring it up is that I am using a function in an API that acts in a similar manner to forEach. I don't want it to keep iterating once it finds a value, and I need to return something so I am simply going to resolve a Promise and do it that way.
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
Then all you need to do is do something with the result like
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
My above example is in typescript, simply ignore the types. The logic should hopefully help you "break" out of your loop.

This isn't the most efficient, since you still cycle all the elements, but I thought it might be worth considering the very simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});

you can follow the code below which works for me:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});

Breaking out of built-in Array.prototype.map function esp in React
The key thing to note here is the use of statement return to BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
More information here: https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript

I know it not right way. It is not break the loop.
It is a Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});

You can create a variant of forEach that allows for break, continue, return, and even async/await: (example written in TypeScript)
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
Usage:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}

I use return false and it works for me.

const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);

Related

Breaking Out Of Recursive Loop JS [duplicate]

[1,2,3].forEach(function(el) {
if(el === 1) break;
});
How can I do this using the new forEach method in JavaScript? I've tried return;, return false; and break. break crashes and return does nothing but continue iteration.
There's no built-in ability to break in forEach. To interrupt execution you would have to throw an exception of some sort. eg.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript exceptions aren't terribly pretty. A traditional for loop might be more appropriate if you really need to break inside it.
Use Array#some
Instead, use Array#some:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
This works because some returns true as soon as any of the callbacks, executed in array order, return true, short-circuiting the execution of the rest.
some, its inverse every (which will stop on a return false), and forEach are all ECMAScript Fifth Edition methods which will need to be added to the Array.prototype on browsers where they're missing.
Use Array#every
[1, 2, 3].every(v => {
if (v > 2) {
return false // "break"
}
console.log(v);
return true // must return true if doesn't break
});
There is now an even better way to do this in ECMAScript2015 (aka ES6) using the new for of loop. For example, this code does not print the array elements after the number 5:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (const el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
From the docs:
Both for...in and for...of statements iterate over something. The main difference between them is in what they iterate over. The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.
Need the index in the iteration? You can use Array.entries():
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
You can use every method:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
for old browser support use:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
more details here.
Quoting from the MDN documentation of Array.prototype.forEach():
There is no way to stop or break a forEach() loop other than
by throwing an exception. If you need such behaviour, the .forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a boolean return value, you can use every() or some() instead.
For your code (in the question), as suggested by #bobince, use Array.prototype.some() instead. It suits very well to your usecase.
Array.prototype.some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
Unfortunately in this case it will be much better if you don't use forEach.
Instead use a regular for loop and it will now work exactly as you would expect.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
From your code example, it looks like Array.prototype.find is what you are looking for: Array.prototype.find() and Array.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Consider to use jquery's each method, since it allows to return false inside callback function:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash libraries also provides takeWhile method that can be chained with map/reduce/fold etc:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []
If you would like to use Dean Edward's suggestion and throw the StopIteration error to break out of the loop without having to catch the error, you can use the following the function (originally from here):
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
The above code will give you the ability to run code such as the following without having to do your own try-catch clauses:
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
One important thing to remember is that this will only update the Array.prototype.forEach function if it already exists. If it doesn't exist already, it will not modify the it.
Short answer: use for...break for this or change your code to avoid breaking of forEach. Do not use .some() or .every() to emulate for...break. Rewrite your code to avoid for...break loop, or use for...break. Every time you use these methods as for...break alternative God kills kitten.
Long answer:
.some() and .every() both return boolean value, .some() returns true if there any element for which passed function returns true, every returns false if there any element for which passed function returns false. This is what that functions mean. Using functions for what they doesn't mean is much worse then using tables for layout instead of CSS, because it frustrates everybody who reads your code.
Also, the only possible way to use these methods as for...break alternative is to make side-effects (change some vars outside of .some() callback function), and this is not much different from for...break.
So, using .some() or .every() as for...break loop alternative isn't free of side effects, this isn't much cleaner then for...break, this is frustrating, so this isn't better.
You can always rewrite your code so that there will be no need in for...break. You can filter array using .filter(), you can split array using .slice() and so on, then use .forEach() or .map() for that part of array.
As mentioned before, you can't break .forEach().
Here's a slightly more modern way of doing a foreach with ES6 Iterators. Allows you to get direct access to index/value when iterating.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Output:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Links
Array.prototype.entries()
Iterators and generators
Destructuring assignment
Another concept I came up with:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
This is just something I came up with to solve the problem... I'm pretty sure it fixes the problem that the original asker had:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
And then you would call it by using:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Returning false inside the callback function will cause a break. Let me know if that doesn't actually work.
If you don't need to access your array after iteration you can bail out by setting the array's length to 0. If you do still need it after your iteration you could clone it using slice..
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Or with a clone:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Which is a far better solution then throwing random errors in your code.
Found this solution on another site. You can wrap the forEach in a try / catch scenario.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
More details here: http://dean.edwards.name/weblog/2006/07/enum/
This is a for loop, but maintains the object reference in the loop just like a forEach() but you can break out.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
try with "find" :
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
Yet another approach:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
I use nullhack for that purpose, it tries to access property of null, which is an error:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
Use the array.prototype.every function, which provide you the utility to break the looping. See example here Javascript documentation on Mozilla developer network
Agree with #bobince, upvoted.
Also, FYI:
Prototype.js has something for this purpose:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break will be catched and handled by Prototype.js internally, breaking the "each" cycle but not generating external errors.
See Prototype.JS API for details.
jQuery also has a way, just return false in the handler to break the loop early:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
See jQuery API for details.
If you want to keep your forEach syntax, this is a way to keep it efficient (although not as good as a regular for loop). Check immediately for a variable that knows if you want to break out of the loop.
This example uses a anonymous function for creating a function scope around the forEach which you need to store the done information.
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
My two cents.
If you need to break based on the value of elements that are already in your array as in your case (i.e. if break condition does not depend on run-time variable that may change after array is assigned its element values) you could also use combination of slice() and indexOf() as follows.
If you need to break when forEach reaches 'Apple' you can use
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
As stated in W3Schools.com the slice() method returns the selected elements in an array, as a new array object. The original array will not be changed.
See it in JSFiddle
Hope it helps someone.
Why don't you try wrapping the function in a Promise?
The only reason I bring it up is that I am using a function in an API that acts in a similar manner to forEach. I don't want it to keep iterating once it finds a value, and I need to return something so I am simply going to resolve a Promise and do it that way.
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
Then all you need to do is do something with the result like
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
My above example is in typescript, simply ignore the types. The logic should hopefully help you "break" out of your loop.
This isn't the most efficient, since you still cycle all the elements, but I thought it might be worth considering the very simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
you can follow the code below which works for me:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Breaking out of built-in Array.prototype.map function esp in React
The key thing to note here is the use of statement return to BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
More information here: https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript
I know it not right way. It is not break the loop.
It is a Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
You can create a variant of forEach that allows for break, continue, return, and even async/await: (example written in TypeScript)
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
Usage:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
I use return false and it works for me.
const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);

JavaScript Return or Break from Array.forEach [duplicate]

[1,2,3].forEach(function(el) {
if(el === 1) break;
});
How can I do this using the new forEach method in JavaScript? I've tried return;, return false; and break. break crashes and return does nothing but continue iteration.
There's no built-in ability to break in forEach. To interrupt execution you would have to throw an exception of some sort. eg.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript exceptions aren't terribly pretty. A traditional for loop might be more appropriate if you really need to break inside it.
Use Array#some
Instead, use Array#some:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
This works because some returns true as soon as any of the callbacks, executed in array order, return true, short-circuiting the execution of the rest.
some, its inverse every (which will stop on a return false), and forEach are all ECMAScript Fifth Edition methods which will need to be added to the Array.prototype on browsers where they're missing.
Use Array#every
[1, 2, 3].every(v => {
if (v > 2) {
return false // "break"
}
console.log(v);
return true // must return true if doesn't break
});
There is now an even better way to do this in ECMAScript2015 (aka ES6) using the new for of loop. For example, this code does not print the array elements after the number 5:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (const el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
From the docs:
Both for...in and for...of statements iterate over something. The main difference between them is in what they iterate over. The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.
Need the index in the iteration? You can use Array.entries():
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
You can use every method:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
for old browser support use:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
more details here.
Quoting from the MDN documentation of Array.prototype.forEach():
There is no way to stop or break a forEach() loop other than
by throwing an exception. If you need such behaviour, the .forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a boolean return value, you can use every() or some() instead.
For your code (in the question), as suggested by #bobince, use Array.prototype.some() instead. It suits very well to your usecase.
Array.prototype.some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
Unfortunately in this case it will be much better if you don't use forEach.
Instead use a regular for loop and it will now work exactly as you would expect.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
From your code example, it looks like Array.prototype.find is what you are looking for: Array.prototype.find() and Array.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Consider to use jquery's each method, since it allows to return false inside callback function:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash libraries also provides takeWhile method that can be chained with map/reduce/fold etc:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []
If you would like to use Dean Edward's suggestion and throw the StopIteration error to break out of the loop without having to catch the error, you can use the following the function (originally from here):
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
The above code will give you the ability to run code such as the following without having to do your own try-catch clauses:
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
One important thing to remember is that this will only update the Array.prototype.forEach function if it already exists. If it doesn't exist already, it will not modify the it.
Short answer: use for...break for this or change your code to avoid breaking of forEach. Do not use .some() or .every() to emulate for...break. Rewrite your code to avoid for...break loop, or use for...break. Every time you use these methods as for...break alternative God kills kitten.
Long answer:
.some() and .every() both return boolean value, .some() returns true if there any element for which passed function returns true, every returns false if there any element for which passed function returns false. This is what that functions mean. Using functions for what they doesn't mean is much worse then using tables for layout instead of CSS, because it frustrates everybody who reads your code.
Also, the only possible way to use these methods as for...break alternative is to make side-effects (change some vars outside of .some() callback function), and this is not much different from for...break.
So, using .some() or .every() as for...break loop alternative isn't free of side effects, this isn't much cleaner then for...break, this is frustrating, so this isn't better.
You can always rewrite your code so that there will be no need in for...break. You can filter array using .filter(), you can split array using .slice() and so on, then use .forEach() or .map() for that part of array.
As mentioned before, you can't break .forEach().
Here's a slightly more modern way of doing a foreach with ES6 Iterators. Allows you to get direct access to index/value when iterating.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Output:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Links
Array.prototype.entries()
Iterators and generators
Destructuring assignment
Another concept I came up with:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
This is just something I came up with to solve the problem... I'm pretty sure it fixes the problem that the original asker had:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
And then you would call it by using:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Returning false inside the callback function will cause a break. Let me know if that doesn't actually work.
If you don't need to access your array after iteration you can bail out by setting the array's length to 0. If you do still need it after your iteration you could clone it using slice..
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Or with a clone:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Which is a far better solution then throwing random errors in your code.
Found this solution on another site. You can wrap the forEach in a try / catch scenario.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
More details here: http://dean.edwards.name/weblog/2006/07/enum/
This is a for loop, but maintains the object reference in the loop just like a forEach() but you can break out.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
try with "find" :
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
Yet another approach:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
I use nullhack for that purpose, it tries to access property of null, which is an error:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
Use the array.prototype.every function, which provide you the utility to break the looping. See example here Javascript documentation on Mozilla developer network
Agree with #bobince, upvoted.
Also, FYI:
Prototype.js has something for this purpose:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break will be catched and handled by Prototype.js internally, breaking the "each" cycle but not generating external errors.
See Prototype.JS API for details.
jQuery also has a way, just return false in the handler to break the loop early:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
See jQuery API for details.
If you want to keep your forEach syntax, this is a way to keep it efficient (although not as good as a regular for loop). Check immediately for a variable that knows if you want to break out of the loop.
This example uses a anonymous function for creating a function scope around the forEach which you need to store the done information.
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
My two cents.
If you need to break based on the value of elements that are already in your array as in your case (i.e. if break condition does not depend on run-time variable that may change after array is assigned its element values) you could also use combination of slice() and indexOf() as follows.
If you need to break when forEach reaches 'Apple' you can use
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
As stated in W3Schools.com the slice() method returns the selected elements in an array, as a new array object. The original array will not be changed.
See it in JSFiddle
Hope it helps someone.
Why don't you try wrapping the function in a Promise?
The only reason I bring it up is that I am using a function in an API that acts in a similar manner to forEach. I don't want it to keep iterating once it finds a value, and I need to return something so I am simply going to resolve a Promise and do it that way.
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
Then all you need to do is do something with the result like
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
My above example is in typescript, simply ignore the types. The logic should hopefully help you "break" out of your loop.
This isn't the most efficient, since you still cycle all the elements, but I thought it might be worth considering the very simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
you can follow the code below which works for me:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Breaking out of built-in Array.prototype.map function esp in React
The key thing to note here is the use of statement return to BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
More information here: https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript
I know it not right way. It is not break the loop.
It is a Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
You can create a variant of forEach that allows for break, continue, return, and even async/await: (example written in TypeScript)
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
Usage:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
I use return false and it works for me.
const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);

How can I break out of a .forEach loop in javascript? [duplicate]

[1,2,3].forEach(function(el) {
if(el === 1) break;
});
How can I do this using the new forEach method in JavaScript? I've tried return;, return false; and break. break crashes and return does nothing but continue iteration.
There's no built-in ability to break in forEach. To interrupt execution you would have to throw an exception of some sort. eg.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript exceptions aren't terribly pretty. A traditional for loop might be more appropriate if you really need to break inside it.
Use Array#some
Instead, use Array#some:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
This works because some returns true as soon as any of the callbacks, executed in array order, return true, short-circuiting the execution of the rest.
some, its inverse every (which will stop on a return false), and forEach are all ECMAScript Fifth Edition methods which will need to be added to the Array.prototype on browsers where they're missing.
Use Array#every
[1, 2, 3].every(v => {
if (v > 2) {
return false // "break"
}
console.log(v);
return true // must return true if doesn't break
});
There is now an even better way to do this in ECMAScript2015 (aka ES6) using the new for of loop. For example, this code does not print the array elements after the number 5:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (const el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
From the docs:
Both for...in and for...of statements iterate over something. The main difference between them is in what they iterate over. The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.
Need the index in the iteration? You can use Array.entries():
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
You can use every method:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
for old browser support use:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
more details here.
Quoting from the MDN documentation of Array.prototype.forEach():
There is no way to stop or break a forEach() loop other than
by throwing an exception. If you need such behaviour, the .forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a boolean return value, you can use every() or some() instead.
For your code (in the question), as suggested by #bobince, use Array.prototype.some() instead. It suits very well to your usecase.
Array.prototype.some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
Unfortunately in this case it will be much better if you don't use forEach.
Instead use a regular for loop and it will now work exactly as you would expect.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
From your code example, it looks like Array.prototype.find is what you are looking for: Array.prototype.find() and Array.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Consider to use jquery's each method, since it allows to return false inside callback function:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash libraries also provides takeWhile method that can be chained with map/reduce/fold etc:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []
If you would like to use Dean Edward's suggestion and throw the StopIteration error to break out of the loop without having to catch the error, you can use the following the function (originally from here):
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
The above code will give you the ability to run code such as the following without having to do your own try-catch clauses:
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
One important thing to remember is that this will only update the Array.prototype.forEach function if it already exists. If it doesn't exist already, it will not modify the it.
Short answer: use for...break for this or change your code to avoid breaking of forEach. Do not use .some() or .every() to emulate for...break. Rewrite your code to avoid for...break loop, or use for...break. Every time you use these methods as for...break alternative God kills kitten.
Long answer:
.some() and .every() both return boolean value, .some() returns true if there any element for which passed function returns true, every returns false if there any element for which passed function returns false. This is what that functions mean. Using functions for what they doesn't mean is much worse then using tables for layout instead of CSS, because it frustrates everybody who reads your code.
Also, the only possible way to use these methods as for...break alternative is to make side-effects (change some vars outside of .some() callback function), and this is not much different from for...break.
So, using .some() or .every() as for...break loop alternative isn't free of side effects, this isn't much cleaner then for...break, this is frustrating, so this isn't better.
You can always rewrite your code so that there will be no need in for...break. You can filter array using .filter(), you can split array using .slice() and so on, then use .forEach() or .map() for that part of array.
As mentioned before, you can't break .forEach().
Here's a slightly more modern way of doing a foreach with ES6 Iterators. Allows you to get direct access to index/value when iterating.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Output:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Links
Array.prototype.entries()
Iterators and generators
Destructuring assignment
Another concept I came up with:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
This is just something I came up with to solve the problem... I'm pretty sure it fixes the problem that the original asker had:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
And then you would call it by using:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Returning false inside the callback function will cause a break. Let me know if that doesn't actually work.
If you don't need to access your array after iteration you can bail out by setting the array's length to 0. If you do still need it after your iteration you could clone it using slice..
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Or with a clone:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Which is a far better solution then throwing random errors in your code.
Found this solution on another site. You can wrap the forEach in a try / catch scenario.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
More details here: http://dean.edwards.name/weblog/2006/07/enum/
This is a for loop, but maintains the object reference in the loop just like a forEach() but you can break out.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
try with "find" :
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
Yet another approach:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
I use nullhack for that purpose, it tries to access property of null, which is an error:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
Use the array.prototype.every function, which provide you the utility to break the looping. See example here Javascript documentation on Mozilla developer network
Agree with #bobince, upvoted.
Also, FYI:
Prototype.js has something for this purpose:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break will be catched and handled by Prototype.js internally, breaking the "each" cycle but not generating external errors.
See Prototype.JS API for details.
jQuery also has a way, just return false in the handler to break the loop early:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
See jQuery API for details.
If you want to keep your forEach syntax, this is a way to keep it efficient (although not as good as a regular for loop). Check immediately for a variable that knows if you want to break out of the loop.
This example uses a anonymous function for creating a function scope around the forEach which you need to store the done information.
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
My two cents.
If you need to break based on the value of elements that are already in your array as in your case (i.e. if break condition does not depend on run-time variable that may change after array is assigned its element values) you could also use combination of slice() and indexOf() as follows.
If you need to break when forEach reaches 'Apple' you can use
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
As stated in W3Schools.com the slice() method returns the selected elements in an array, as a new array object. The original array will not be changed.
See it in JSFiddle
Hope it helps someone.
Why don't you try wrapping the function in a Promise?
The only reason I bring it up is that I am using a function in an API that acts in a similar manner to forEach. I don't want it to keep iterating once it finds a value, and I need to return something so I am simply going to resolve a Promise and do it that way.
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
Then all you need to do is do something with the result like
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
My above example is in typescript, simply ignore the types. The logic should hopefully help you "break" out of your loop.
This isn't the most efficient, since you still cycle all the elements, but I thought it might be worth considering the very simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
you can follow the code below which works for me:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Breaking out of built-in Array.prototype.map function esp in React
The key thing to note here is the use of statement return to BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
More information here: https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript
I know it not right way. It is not break the loop.
It is a Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
You can create a variant of forEach that allows for break, continue, return, and even async/await: (example written in TypeScript)
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
Usage:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
I use return false and it works for me.
const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);

Breaking with return false from forEach loop [duplicate]

[1,2,3].forEach(function(el) {
if(el === 1) break;
});
How can I do this using the new forEach method in JavaScript? I've tried return;, return false; and break. break crashes and return does nothing but continue iteration.
There's no built-in ability to break in forEach. To interrupt execution you would have to throw an exception of some sort. eg.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScript exceptions aren't terribly pretty. A traditional for loop might be more appropriate if you really need to break inside it.
Use Array#some
Instead, use Array#some:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
This works because some returns true as soon as any of the callbacks, executed in array order, return true, short-circuiting the execution of the rest.
some, its inverse every (which will stop on a return false), and forEach are all ECMAScript Fifth Edition methods which will need to be added to the Array.prototype on browsers where they're missing.
Use Array#every
[1, 2, 3].every(v => {
if (v > 2) {
return false // "break"
}
console.log(v);
return true // must return true if doesn't break
});
There is now an even better way to do this in ECMAScript2015 (aka ES6) using the new for of loop. For example, this code does not print the array elements after the number 5:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (const el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
From the docs:
Both for...in and for...of statements iterate over something. The main difference between them is in what they iterate over. The for...in statement iterates over the enumerable properties of an object, in original insertion order. The for...of statement iterates over data that iterable object defines to be iterated over.
Need the index in the iteration? You can use Array.entries():
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
You can use every method:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
for old browser support use:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
more details here.
Quoting from the MDN documentation of Array.prototype.forEach():
There is no way to stop or break a forEach() loop other than
by throwing an exception. If you need such behaviour, the .forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a boolean return value, you can use every() or some() instead.
For your code (in the question), as suggested by #bobince, use Array.prototype.some() instead. It suits very well to your usecase.
Array.prototype.some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value (a value that becomes true when converted to a Boolean). If such an element is found, some() immediately returns true. Otherwise, some() returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
Unfortunately in this case it will be much better if you don't use forEach.
Instead use a regular for loop and it will now work exactly as you would expect.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
From your code example, it looks like Array.prototype.find is what you are looking for: Array.prototype.find() and Array.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Consider to use jquery's each method, since it allows to return false inside callback function:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Lodash libraries also provides takeWhile method that can be chained with map/reduce/fold etc:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []
If you would like to use Dean Edward's suggestion and throw the StopIteration error to break out of the loop without having to catch the error, you can use the following the function (originally from here):
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
The above code will give you the ability to run code such as the following without having to do your own try-catch clauses:
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
One important thing to remember is that this will only update the Array.prototype.forEach function if it already exists. If it doesn't exist already, it will not modify the it.
Short answer: use for...break for this or change your code to avoid breaking of forEach. Do not use .some() or .every() to emulate for...break. Rewrite your code to avoid for...break loop, or use for...break. Every time you use these methods as for...break alternative God kills kitten.
Long answer:
.some() and .every() both return boolean value, .some() returns true if there any element for which passed function returns true, every returns false if there any element for which passed function returns false. This is what that functions mean. Using functions for what they doesn't mean is much worse then using tables for layout instead of CSS, because it frustrates everybody who reads your code.
Also, the only possible way to use these methods as for...break alternative is to make side-effects (change some vars outside of .some() callback function), and this is not much different from for...break.
So, using .some() or .every() as for...break loop alternative isn't free of side effects, this isn't much cleaner then for...break, this is frustrating, so this isn't better.
You can always rewrite your code so that there will be no need in for...break. You can filter array using .filter(), you can split array using .slice() and so on, then use .forEach() or .map() for that part of array.
As mentioned before, you can't break .forEach().
Here's a slightly more modern way of doing a foreach with ES6 Iterators. Allows you to get direct access to index/value when iterating.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Output:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Links
Array.prototype.entries()
Iterators and generators
Destructuring assignment
Another concept I came up with:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
This is just something I came up with to solve the problem... I'm pretty sure it fixes the problem that the original asker had:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
And then you would call it by using:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Returning false inside the callback function will cause a break. Let me know if that doesn't actually work.
If you don't need to access your array after iteration you can bail out by setting the array's length to 0. If you do still need it after your iteration you could clone it using slice..
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Or with a clone:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Which is a far better solution then throwing random errors in your code.
Found this solution on another site. You can wrap the forEach in a try / catch scenario.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
More details here: http://dean.edwards.name/weblog/2006/07/enum/
This is a for loop, but maintains the object reference in the loop just like a forEach() but you can break out.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
try with "find" :
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
Yet another approach:
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
I use nullhack for that purpose, it tries to access property of null, which is an error:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
Use the array.prototype.every function, which provide you the utility to break the looping. See example here Javascript documentation on Mozilla developer network
Agree with #bobince, upvoted.
Also, FYI:
Prototype.js has something for this purpose:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break will be catched and handled by Prototype.js internally, breaking the "each" cycle but not generating external errors.
See Prototype.JS API for details.
jQuery also has a way, just return false in the handler to break the loop early:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
See jQuery API for details.
If you want to keep your forEach syntax, this is a way to keep it efficient (although not as good as a regular for loop). Check immediately for a variable that knows if you want to break out of the loop.
This example uses a anonymous function for creating a function scope around the forEach which you need to store the done information.
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
My two cents.
If you need to break based on the value of elements that are already in your array as in your case (i.e. if break condition does not depend on run-time variable that may change after array is assigned its element values) you could also use combination of slice() and indexOf() as follows.
If you need to break when forEach reaches 'Apple' you can use
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
As stated in W3Schools.com the slice() method returns the selected elements in an array, as a new array object. The original array will not be changed.
See it in JSFiddle
Hope it helps someone.
Why don't you try wrapping the function in a Promise?
The only reason I bring it up is that I am using a function in an API that acts in a similar manner to forEach. I don't want it to keep iterating once it finds a value, and I need to return something so I am simply going to resolve a Promise and do it that way.
traverseTree(doc): Promise<any> {
return new Promise<any>((resolve, reject) => {
this.gridOptions.api.forEachNode((node, index) => {
//the above function is the one I want to short circuit.
if(node.data.id === doc.id) {
return resolve(node);
}
});
});
}
Then all you need to do is do something with the result like
this.traverseTree(doc).then((result) => {
this.doSomething(result);
});
My above example is in typescript, simply ignore the types. The logic should hopefully help you "break" out of your loop.
This isn't the most efficient, since you still cycle all the elements, but I thought it might be worth considering the very simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
you can follow the code below which works for me:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Breaking out of built-in Array.prototype.map function esp in React
The key thing to note here is the use of statement return to BREAK
let isBroken = false;
colours.map(item => {
if (isBroken) {
return;
}
if (item.startsWith("y")) {
console.log("The yessiest colour!");
isBroken = true;
return;
}
});
More information here: https://www.codegrepper.com/code-examples/javascript/break+out+of+map+javascript
I know it not right way. It is not break the loop.
It is a Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
You can create a variant of forEach that allows for break, continue, return, and even async/await: (example written in TypeScript)
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
Usage:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
I use return false and it works for me.
const Book = {"Titles":[
{"Book3" : "BULLETIN 3"},
{"Book1" : "BULLETIN 1"},
{"Book2" : "BULLETIN 2"}
]}
const findbystr = function(str) {
Book.Titles.forEach(function(data) {
if (typeof data[str] != 'undefined') {
return data[str];
}
}, str)
}
book = findbystr('Book1');
console.log(book);

Why does this forEach return undefined when using a return statement

Object.prototype.e = function() {
[].forEach.call(this, function(e) {
return e;
});
};
var w = [1,2];
w.e(); // undefined
But this works if I use alert instead
// ...
[].forEach.call(this, function(e) {
alert(e);
});
// ...
w.e(); // 1, 2
I realize this is an old question, but as it's the first thing that comes up on google when you search about this topic, I'll mention that what you're probably looking for is javascript's for.. in loop, which behaves closer to the for-each in many other languages like C#, C++, etc...
for(var x in enumerable) { /*code here*/ }
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in
http://jsfiddle.net/danShumway/e4AUK/1/
A couple of things to remember :
for..in will not guarantee that your data will be returned in any particular order.
Your variable will still refer to the index, not the actual value stored at that index.
Also see below comments about using this with arrays.
edit: for..in will return (at the least) added properties to the prototype of an object. If this is undesired, you can correct for this behavior by wrapping your logic in an additional check:
for(var x in object) {
if(object.hasOwnProperty(x)) {
console.log(x + ": " + object[x]);
}
}
Your example is a bit odd, but as this question is becoming the canonical "return from forEach" question, let's use something simpler to demonstrate the problem:
Here, we have a function that checks the entries in an array to see if someProp matches value and, if so, increments the count on the entry and returns the entry:
function updateAndReturnMatch(array, value) {
array.forEach(function(entry) {
if (entry.someProp == value) {
++entry.count;
return entry;
}
});
}
But calling updateAndReturnMatch gives us undefined, even if the entry was found and updated.
The reason is that the return inside the forEach callback returns from the callback, not from updateAndReturnMatch. Remember, the callback is a function; return in a function returns from that function, not the one containing it.
To return from updateAndReturnMatch, we need to remember the entry and break the loop. Since you can't break a forEach loop, we'll use some instead:
function updateAndReturnMatch(array, value) {
var foundEntry;
array.some(function(entry) {
if (entry.someProp == value) {
foundEntry = entry;
++foundEntry.count;
return true; // <== Breaks out of the `some` loop
}
});
return foundEntry;
}
The return true returns from our some callback, and the return foundEntry returns from updateAndReturnMatch.
Sometimes that's what you want, but often the pattern above can be replaced with Array#find, which is new in ES2015 but can be shimmed for older browsers:
function updateAndReturnMatch(array, value) {
var foundEntry = array.find(function(entry) {
return entry.someProp == value;
});
if (foundEntry) {
++foundEntry.count;
}
return foundEntry;
}
The function e() isn't returning anything; the inner anonymous function is returning its e value but that return value is being ignored by the caller (the caller being function e() (and can the multiple uses of 'e' get any more confusing?))
Because
function(e) {
return e;
}
is a callback. Array.forEach most likely calls it in this fashion:
function forEach(callback) {
for(i;i<length;i++) {
item = arr[i];
callback.call(context, item, i, etc.)
}
}
so the call back is called, but the return doesn't go anywhere. If callback were called like:
return callback.call();
the it would return out of forEach on the first item in the array.
You can use for...of to loop over iterable objects, like array, string, map, set... as per Mozilla docs.
const yourArray = [1, 2, 3]
for (const el of yourArray) { // or yourMap, Set, String etc..
if (el === 2) {
return "something"; // this will break the loop
}
}

Categories