Categories
arrays foreach javascript

Short circuit Array.forEach like calling break

2031

[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.

1

  • 23

    It is worth noting that while return does indeed continue the iteration, it will skip any code that comes after it in the block. Take this code for instance: [1,2,3].forEach(function(el) { if(el === 2) { console.log(`Match on 2!`); return; } console.log(el); }); .The console.log(el); will be skipped when 2 is matched.

    Aug 2, 2019 at 16:31


2682

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.

16

  • 55

    I think “some” is fine here, why not use the early exit optimization-

    – chrismarx

    Mar 2, 2016 at 16:47


  • 51

    Thanks for minding some and every, this should be on TOP in the answer. Can’t understand why people think it’s less readable. It’s just awesome!

    Mar 2, 2017 at 14:15

  • 14

    The use of Array#some is really nice. Firstly its compatible with most browsers including ie9 and firefox 1.5 also works really well. My example use case will be to find the index in an array of ranges[a,b] where a number is between a lower boundary and upper boundary pair, test and return true when found. for..of would be the next best solution though only for newer browsers.

    – Sojimaxi

    Nov 2, 2017 at 16:08

  • 212

    Exception handling should NEVER be used as control flow. PERIOD.

    – frank

    Nov 10, 2017 at 23:00

  • 11

    @frank I wrote an esolang with only one loop construct: forever. All other loop constructs are formed from forever and appropriate iterable exceptions, such as ContinueIteration and StopIteration (which break is a macro to raise). On one hand: never. On the other hand: always. On the gripping hand: sometimes? The “PERIOD” in your comment implies there may be a citation to back up your suggestion?

    – amcgregor

    Oct 31, 2018 at 18:03

749

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;
}

8

  • 8

    @superhero You can get the index of the element in a for…of loop, you just have to use entries. for (const [index, element] of someArray.entries()) { // … }

    Jan 19, 2018 at 13:19


  • 1

    isn’t it recommended not to use for…in with arrays ?

    – shehata

    Jun 20, 2018 at 15:19

  • 7

    @emostafa You are correct about for in loops not being recommended for arrays, but this is approach actually uses a for of loop.

    – canac

    Jun 21, 2018 at 17:33

  • 1

    This is “for of”, and this is a really clean solution… but this is also an ES6 feature, so just be aware that this will only work if your environment is setup for ES6.

    – Chad

    Jul 16, 2019 at 18:10

  • 1

    Perhaps better to use “const” instead of “let” 🙂

    – Ellis

    Jul 26 at 8:44

235

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.

10

  • 12

    Nice and clean in ES6 now – [1,2,3].every( el => el !== 1 )

    – metame

    Jan 4, 2017 at 5:11

  • 1

    @Valdemar, But does every guarantee that calls are made in sequence?

    – Pacerier

    Apr 2, 2017 at 9:25


  • 4

    @Pacerier, you can see the algorithm in the ES6 specification that the index k starts at 0 and is incremented by 1: http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.every

    – XP1

    Jun 26, 2017 at 0:51

  • 1

    @Pacerier, yes, most popular implementations work properly. If you are concerned about embedded implementations, usually it’s Opera or webkit. Method every calls callbackfn once for each element present in the array, in ascending order, until it finds one where callbackfn returns false. Also look at step 7. Let k be 0. and 8.e Increase k by 1.

    Aug 8, 2017 at 6:39

  • 1

    Changes the intention of the code. Very bad.

    – Cesar

    Feb 28, 2021 at 11:23