JavaScript – forEach with Breaking

 


It seems that one of the top complaints about the Array.prototype.forEach() function is the fact that there is no easy way to break out of the loop. If you are one of those people that would like to see an implementation, here you go:

function forEach(arr, fn, thisObj) {
  // Try-catch surrounds the loop to allow throwing the array as an equivalent
  // for breaking out of the loop.
  try {
    for(var i = 0, len = arr.length; i < len; i++) {
      fn.call(thisObj, arr[i], i, arr);
    }
  }
  catch(e) {
    // If the error thrown was not the array, allow the error to continue up the
    // stack.
    if(e !== arr) {
      throw e;
    }
  }
  
  // Return a reference to the array to all for further manipulation.
  return arr;
}

Calling this function would be similar to using Array.prototype.forEach.call() to call the forEach() function introduced in JavaScript 1.6. Here is an example call will break out of the loop as soon a perfect square is found:

var perfectSquare;
forEach([2,3,5,6,7,8,9,10,16], function(num, index, arr) {
  var sqrt = Math.sqrt(num);
  if(sqrt == parseInt(sqrt, 10)) {
    perfectSquare = num;
    throw arr;
  }
});

alert(perfectSquare);  // first perfect square found

For proof that this actually works, you can check out this JSBin page.

As you see in the code, in order to break out of the loop, you will need to throw the array that you are traversing. As you may have guessed, you can also fake the continue action by simply using return.

 

4 thoughts on “JavaScript – forEach with Breaking”

  1. 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:

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

Leave a Reply

Your email address will not be published. Required fields are marked *


four − = 3

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="">