recorrer es6 array javascript arrays

javascript - es6 - Corto circuito Array.forEach como llamar a break



javascript foreach object (28)

Ahora hay una forma aún mejor de hacerlo en ECMAScript2015 (también conocido como ES6) utilizando el nuevo bucle for . Por ejemplo, este código no imprime los elementos de la matriz después del número 5:

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let el of arr) { console.log(el); if (el === 5) { break; } }

De la documentación:

Tanto para ... en y para ... de declaraciones iterar sobre algo. La principal diferencia entre ellos está en lo que se repite. La instrucción for ... in itera sobre las propiedades enumerables de un objeto, en el orden de inserción original. La sentencia for ... de iteración sobre datos que el objeto iterable define para ser iterada.

¿Necesitas el índice en la iteración? Puedes usar Array.entries() :

for (const [index, el] of arr.entries()) { if ( index === 5 ) break; }

[1,2,3].forEach(function(el) { if(el === 1) break; });

¿Cómo puedo hacer esto usando el nuevo método forEach en JavaScript? He intentado return; , return false; y break break choques y return no hace más que continuar la iteración.


Como se mencionó anteriormente, no puedes romper .forEach() .

Aquí hay una forma ligeramente más moderna de hacer un foreach con los iteradores ES6. Le permite obtener acceso directo al index / value al iterar.

const array = [''one'', ''two'', ''three'']; for (const [index, val] of array.entries()) { console.log(''item:'', { index, val }); if (index === 1) { console.log(''break!''); break; } }

Salida:

item: { index: 0, val: ''one'' } item: { index: 1, val: ''two'' } break!

Campo de golf


Considere utilizar each método de jquery , ya que permite devolver una función de devolución de llamada interna falsa:

$.each(function(e, i) { if (i % 2) return false; console.log(e) })

Las bibliotecas de Lodash también proporcionan el método takeWhile que se puede encadenar con 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''); // => []


Cotización de la documentación MDN de Array.prototype.forEach() :

No hay forma de detener o romper un bucle forEach() no sea lanzar una excepción. Si necesita tal comportamiento, el método .forEach() es la herramienta incorrecta , use un bucle plano en su lugar. Si está probando los elementos de la matriz para un predicado y necesita un valor de retorno booleano, puede usar every() o some() lugar.

Para su código (en la pregunta), como lo sugiere @bobince, use some() lugar. Se adapta muy bien a tu caso de uso.

Array.prototype.some() ejecuta la función de devolución de llamada una vez para cada elemento presente en la matriz hasta que encuentra uno en el que la devolución de llamada devuelve un valor verdadero (un valor que se convierte en verdadero cuando se convierte a Boolean ). Si se encuentra un elemento de este tipo, some() devuelve inmediatamente true. De lo contrario, some() devuelve false. la devolución de llamada se invoca solo para los índices de la matriz que tienen valores asignados; no se invoca para los índices que se han eliminado o que nunca se han asignado valores.


De acuerdo con @bobince, upvoted.

Además, para su información:

Prototype.js tiene algo para este propósito:

<script type="text/javascript"> $$(''a'').each(function(el, idx) { if ( /* break condition */ ) throw $break; // do something }); </script>

$break será capturado y manejado por Prototype.js internamente, rompiendo el ciclo "cada uno" pero no generando errores externos.

Ver Prototype.JS API para más detalles.

jQuery también tiene una forma, simplemente devuelve falso en el controlador para interrumpir el ciclo temprano:

<script type="text/javascript"> jQuery(''a'').each( function(idx) { if ( /* break condition */ ) return false; // do something }); </script>

Ver jQuery API para más detalles.


Desafortunadamente, en este caso será mucho mejor si no usa forEach . En su lugar, use un bucle for regular y ahora funcionará exactamente como lo esperaría.

var array = [1, 2, 3]; for (var i = 0; i < array.length; i++) { if (array[i] === 1){ break; } }



Encontré esta solución en otro sitio. Puedes envolver el forEach en un escenario de prueba / captura.

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

Más detalles aquí: http://dean.edwards.name/weblog/2006/07/enum/


Este es un bucle for, pero mantiene la referencia del objeto en el bucle al igual que un forEach () pero se puede romper.

var arr = [1,2,3]; for (var i = 0, el; el = arr[i]; i++) { if(el === 1) break; }


Esto es algo que se me ocurrió para resolver el problema ... Estoy bastante seguro de que soluciona el problema que tenía el autor de la pregunta original:

Array.prototype.each = function(callback){ if(!callback) return false; for(var i=0; i<this.length; i++){ if(callback(this[i], i) == false) break; } };

Y luego lo llamarías usando:

var myarray = [1,2,3]; myarray.each(function(item, index){ // do something with the item // if(item != somecondition) return false; });

Devolver falso dentro de la función de devolución de llamada causará una interrupción. Déjame saber si eso realmente no funciona.


Esto no es lo más eficiente, ya que aún tienes ciclos de todos los elementos, pero pensé que valdría la pena considerar el muy simple:

let keepGoing = true; things.forEach( (thing) => { if (noMore) keepGoing = false; if (keepGoing) { // do things with thing } });


La respuesta correcta depende de por qué quieres hacer esto.

Si lo que desea es: "una forma tan limpia y concisa de salir de forEach() como sea posible, dado que no se permite la break " , puede redefinir Array.forEach () para permitirle hacer esto:

[1,2,3,4,5].forEach((x,i,stop) => { // x and i are the standard 2 args if (x > 3) { stop() // You could call it ''end'', ''brk'' or whatever... } console.log(x) })

Aquí está la anulación, tenga en cuenta que forEach() normalmente pasa dos parámetros: el objeto iterado actualmente y el índice. Solo estamos agregando un tercero:

Array.prototype.forEach = function(fn) { var StopIteration = new Error("StopIteration"); var len = this.length; function stop() { throw StopIteration; } for (i=0;i<len;i++) { try { fn(this[i], i, stop) } catch(e) { if(e == StopIteration) { return } throw e; } } }

Puede usar el nombre que desee (excepto break , o cualquier otra palabra clave reservada, ¡no hay suerte!)

(En un proyecto real, debería ir con una de las respuestas súper elevadas. Solo estoy agregando esto porque algunas personas pueden encontrar el concepto útil en otras aplicaciones).


Lo sé no de la manera correcta. No es romper el bucle. Es un jugad

let result = true; [1, 2, 3].forEach(function(el) { if(result){ console.log(el); if (el === 2){ result = false; } } });


No hay una habilidad incorporada para break por cada forEach . Para interrumpir la ejecución, tendría que lanzar una excepción de algún tipo. p.ej.

var BreakException = {}; try { [1, 2, 3].forEach(function(el) { console.log(el); if (el === 2) throw BreakException; }); } catch (e) { if (e !== BreakException) throw e; }

Las excepciones de JavaScript no son terriblemente bonitas. Un bucle for tradicional podría ser más apropiado si realmente necesitas break dentro de él.

Use Array#some

En su lugar, use Array#some :

[1, 2, 3].some(function(el) { console.log(el); return el === 2; });

Esto funciona porque some devuelven true tan pronto como cualquiera de las devoluciones de llamada, ejecutadas en orden de matriz, devuelven true , cortocircuitando la ejecución del resto.

some , son every inversos (que se detendrán en una return false ), y para cada forEach son todos los métodos de ECMAScript Fifth Edition que se deben agregar al Array.prototype en los navegadores donde faltan.


Otro concepto que se me ocurrió:

function forEach(array, cb) { var breakOnNext = false; function _break() { breakOnNext = true; } for (var i = 0, bound = array.length; i < bound; ++i) { if (breakOnNext) { break; } cb(array[i], i, array, _break); } }

Uso:

forEach([''a'',''b'',''c'',''d''], function (e, i, array, _break) { console.log(e, i); if (e === ''b'') { _break(); } });

Es posible que necesite algunos ajustes, especialmente para admitir la iteración de la propiedad del objeto.


Otro enfoque mas

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


Prefiero usar for in

var words = [''a'', ''b'', ''c'']; var text = ''''; for (x in words) { if (words[x] == ''b'') continue; text += words[x]; } console.log(text);

for in funciona de manera muy similar a forEach , y puede agregar return para salir dentro de la función. Mejor rendimiento también.


Puedes seguir el siguiente código que me funciona:

var loopStop = false; YOUR_ARRAY.forEach(function loop(){ if(loopStop){ return; } if(condition){ loopStop = true; } });


Puedes usar every métodos:

[1,2,3].every(function(el) { return !(el === 1); });

para usar el viejo navegador:

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

Más detalles here .


Respuesta corta: use for...break para esto o cambie su código para evitar la ruptura de forEach . No use .some() o .every() para emular for...break . Vuelva a escribir su código para evitar for...break bucle, o usar for...break . Cada vez que usas estos métodos for...break alternativa Dios mata al gatito.

Respuesta larga:

.some() y .every() devuelven ambos valores boolean , .some() devuelve true si hay algún elemento para el que la función pasada devuelve true , todo devuelve false si hay algún elemento para el que la función pasada devuelve false . Esto es lo que significan las funciones. Usar funciones para lo que no significan es mucho peor que usar tablas para maquetar en lugar de CSS, porque frustra a todos los que leen tu código.

Además, la única forma posible de utilizar estos métodos como alternativa a la for...break es crear efectos secundarios (cambiar algunas variables fuera de la función de devolución de llamada .some() ), y esto no es muy diferente de la for...break .

Por lo tanto, usar .some() o .every() for...break alternativa de bucle de for...break no está exenta de efectos secundarios, esto no es mucho más limpio que la for...break , esto es frustrante, por lo que no es mejor.

Siempre puede volver a escribir su código para que no haya necesidad for...break . Puede filtrar la matriz usando .filter() , puede dividir la matriz usando .slice() y así sucesivamente, y luego usar .forEach() o .map() para esa parte de la matriz.


Si desea mantener su sintaxis de forEach , esta es una manera de mantenerla eficiente (aunque no tan buena como un bucle regular). Verifique de inmediato si hay una variable que sepa si quiere salir del ciclo.

Este ejemplo utiliza una función anónima para crear un ámbito de función alrededor del forEach que necesita para almacenar la información realizada .

(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>

Mis dos centavos.


Si desea utilizar la sugerencia de Dean Edward y lanzar el error StopIteration para salir del ciclo sin tener que detectar el error, puede usar la siguiente función ( originalmente desde aquí ):

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

El código anterior le dará la capacidad de ejecutar código como el siguiente sin tener que hacer sus propias cláusulas try-catch:

// Show the contents until you get to "2". [0,1,2,3,4].forEach(function(val) { if(val == 2) throw StopIteration; alert(val); });

Una cosa importante a recordar es que esto solo actualizará la función Array.prototype.forEach si ya existe. Si no existe ya, no lo modificará.


Si necesita una ruptura basada en el valor de los elementos que ya están en su matriz como en su caso (es decir, si la condición de ruptura no depende de la variable de tiempo de ejecución que puede cambiar después de que la matriz tenga asignados sus valores de elementos), también puede usar la combinación de slice() y indexOf() siguiente manera.

Si necesitas romper cuando forEach llega a ''Apple'' puedes usar

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

Como se indica slice() el método slice () devuelve los elementos seleccionados en una matriz, como un nuevo objeto de matriz. La matriz original no se cambiará.

JSFiddle en JSFiddle

Espero que ayude a alguien.


Si no necesita acceder a su matriz después de la iteración, puede rescatarla estableciendo la longitud de la matriz en 0. Si todavía la necesita después de su iteración, puede clonarla utilizando la división.

[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) { if (index === 3) arr.length = 0; });

O con un clon:

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

Que es una solución mucho mejor que lanzar errores aleatorios en su código.



Yo uso nullhack para ese propósito, intenta acceder a la propiedad de null , que es un 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 } //


prueba con "encontrar":

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


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