breakできるforEach ―throwを使って―
思いつき。break文のように入れ子になった内側のループの中から外側のループも抜けられるように。
function Break(target) { this.target = target; } function forEach(array, callbackfn, thisArg) { try { Array.prototype.forEach.call(array, callbackfn, thisArg); } catch (e) { if (!(e instanceof Break) || (e.target && e.target !== callbackfn)) { throw e; } } }
使用例は以下の通り。
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9]; forEach(array, function (n) { console.log(n); if (n === 5) { // 引数を指定しなければ直近のforEachが止まる throw new Break(); } }); forEach(array, function outer(i) { forEach(array, function inner(j) { console.log('%d * %d = %d', i, j, i * j); if (i === 5 && j === 5) { // 引数を指定するとその関数をコールバックとして渡したforEachが止まる throw new Break(outer); } }); });
戻り値 === false
で判断する方法は、reduceやfilterのような戻り値が意味を持つメソッドには使えない。一方、このthrow文の方法なら区別できる。でも、やっぱりここでthrow文は変な感じ。
someをforEach代わりに使うのも変な感じがする(と言いつつよくやるけど)。mapがあればforEachいらないよね、戻り値を無視すればいいだけなんだから、みたいな。
いっそのこと……
Array.prototype.forEach = Array.prototype.some;
Underscore.js、breaker変数をpublicにすればいいのに。