[1,2,3].forEach(function(el) {
if(el === 1) break;
});
Como posso fazer isso usando o novo forEach
método em JavaScript? Eu tentei return;
, return false;
e break
. break
trava e return
não faz nada além de continuar a iteração.
[1,2,3].forEach(function(el) {
if(el === 1) break;
});
Como posso fazer isso usando o novo forEach
método em JavaScript? Eu tentei return;
, return false;
e break
. break
trava e return
não faz nada além de continuar a iteração.
Respostas:
Não há como built-in capacidade de break
nos forEach
. Para interromper a execução, você teria que lançar uma exceção de algum tipo. por exemplo.
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
As exceções de JavaScript não são muito bonitas. Um for
loop tradicional pode ser mais apropriado se você realmente precisar break
dele.
Array#some
Em vez disso, use Array#some
:
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
Isso funciona porque some
retorna true
assim que qualquer retorno de chamada, executado em ordem de matriz, retorna true
, causando um curto-circuito na execução do restante.
some
, é inverso every
(que será interrompido em a return false
) e forEach
são todos os métodos do ECMAScript Fifth Edition que precisarão ser adicionados aos Array.prototype
navegadores nos quais estão ausentes.
some
e every
, isso deve estar no TOP na resposta. Não consigo entender por que as pessoas pensam que é menos legível. É simplesmente incrível!
Array#some
é muito bom. Em primeiro lugar, é compatível com a maioria dos navegadores, incluindo ie9 e firefox 1.5, também funciona muito bem. Meu exemplo de caso de uso será encontrar o índice em uma matriz de intervalos [a, b] em que um número esteja entre um par de limite inferior e superior, testar e retornar true quando encontrado. for..of
seria a próxima melhor solução, embora apenas para navegadores mais recentes.
Agora existe uma maneira ainda melhor de fazer isso no ECMAScript2015 (também conhecido como ES6) usando o novo loop for . Por exemplo, este código não imprime os elementos da matriz após o 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;
}
}
Dos documentos:
Tanto para ... como para ... das declarações repetem algo. A principal diferença entre eles está no que eles repetem. A instrução for ... itera sobre as propriedades enumeráveis de um objeto, na ordem de inserção original. A instrução for ... itera sobre os dados que o objeto iterável define para ser iterado.
Precisa do índice na iteração? Você pode usar Array.entries()
:
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
entries
. para (const [index, elemento] de someArray.entries ()) {// ...}
Você pode usar todos os métodos:
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
para suporte ao navegador antigo, 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;
};
}
mais detalhes aqui .
[1,2,3].every( el => el !== 1 )
every
garante que as chamadas sejam feitas em sequência?
k
inicia em 0 e é incrementado por 1: http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.every
Citando a partir da documentação MDN deArray.prototype.forEach()
:
Não há como parar ou interromper um
forEach()
loop além de lançar uma exceção. Se você precisar desse comportamento, o.forEach()
método é a ferramenta errada , use um loop simples. Se você estiver testando os elementos da matriz em busca de um predicado e precisar de um valor de retorno booleano, poderá usarevery()
ou emsome()
vez disso.
Para o seu código (na pergunta), conforme sugerido por @bobince, use em seu Array.prototype.some()
lugar. Serve muito bem para o seu caso.
Array.prototype.some()
executa a função de retorno de chamada uma vez para cada elemento presente na matriz até encontrar um em que o retorno de chamada retorne um valor verdadeiro (um valor que se torna verdadeiro quando convertido em aBoolean
). Se esse elemento for encontrado,some()
retornará imediatamente true. Caso contrário,some()
retorna false. o retorno de chamada é invocado apenas para índices da matriz que atribuíram valores; não é invocado para índices que foram excluídos ou aos quais nunca foram atribuídos valores.
Infelizmente, neste caso, será muito melhor se você não usar forEach
. Em vez disso, use um for
loop regular e agora funcionará exatamente como você esperaria.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
Considere usar jquery
o each
método, pois permite retornar a função de retorno de chamada interna falsa:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
As bibliotecas Lodash também fornecem um takeWhile
método que pode ser encadeado com 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');
// => []
No seu exemplo de código, parece Array.prototype.find
que você está procurando: Array.prototype.find () e Array.prototype.findIndex ()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Se você quiser usar a sugestão de Dean Edward e lançar o erro StopIteration para interromper o loop sem precisar capturar o erro, use a seguinte função ( originalmente daqui ):
// 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;
}
}
};
}
})();
O código acima permitirá executar códigos como os seguintes, sem a necessidade de fazer suas próprias 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);
});
Uma coisa importante a lembrar é que isso só atualizará a função Array.prototype.forEach se ela já existir. Se ainda não existir, não será modificado.
Resposta curta: use for...break
para isso ou altere seu código para evitar a quebra de forEach
. Não use .some()
ou .every()
para emular for...break
. Reescreva seu código para evitar for...break
loop ou use for...break
. Toda vez que você usa esses métodos como for...break
alternativa, Deus mata um gatinho.
Resposta longa:
.some()
e .every()
ambos retornam boolean
valor, .some()
retornam true
se houver algum elemento para o qual a função passada retorne true
, todos retornarão false
se houver algum elemento para o qual a função passada retorne false
. É isso que essas funções significam. Usar funções para o que elas não significam é muito pior do que usar tabelas para layout em vez de CSS, porque frustra todo mundo que lê seu código.
Além disso, a única maneira possível de usar esses métodos como for...break
alternativa é produzir efeitos colaterais (alterar alguns vars fora da .some()
função de retorno de chamada), e isso não é muito diferente for...break
.
Portanto, usar .some()
ou .every()
como for...break
alternativa de loop não está isento de efeitos colaterais, não é muito mais limpo for...break
, é frustrante, então não é melhor.
Você sempre pode reescrever seu código para que não haja necessidade for...break
. Você pode filtrar a matriz usando .filter()
, pode dividir a matriz usando .slice()
e assim por diante, depois usar .forEach()
ou .map()
para essa parte da matriz.
for...break
loop se precisar de desempenho. for
laço é a ferramenta mais perfeita do que iteração .forEach()
, .any()
, .map()
, .filter()
etc
Isso é apenas algo que eu criei para resolver o problema ... Tenho certeza de que corrige o problema que o solicitante original tinha:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
E então você chamaria usando:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Retornar false dentro da função de retorno de chamada causará uma interrupção. Deixe-me saber se isso realmente não funciona.
=== false
pode ser melhor do que == false
isso, para que você não precise retornar explicitamente true (ou um valor verdadeiro) para continuar o loop, para que algum caminho de controle não retorne um valor e o loop quebre inesperadamente.
Outro conceito que surgiu:
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(); }
});
Array.prototype.forEach()
. for
e break
existia muito antes desta pergunta ser feita; o OP estava procurando esse comportamento usando, o mais funcional forEach
,.
for...in
e break
.
var array = [1,2,3,4];
for(var item of array){
console.log(item);
if(item == 2){
break;
}
}
Encontrei esta solução em outro site. Você pode agrupar o forEach em um cenário de tentativa / 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; }
Mais detalhes aqui: http://dean.edwards.name/weblog/2006/07/enum/
Se você não precisar acessar sua matriz após a iteração, poderá resgatar definindo o comprimento da matriz como 0. Se ainda precisar dela após a iteração, poderá cloná-la usando a fatia.
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Ou com um 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;
});
Qual é uma solução muito melhor do que lançar erros aleatórios no seu código.
array.length
a 0
elas se aplicarão em iteração atual, então provavelmente às vezes é melhor usar return
depois de tal atribuição
Como mencionado anteriormente, você não pode quebrar .forEach()
.
Aqui está uma maneira um pouco mais moderna de fazer um foreach com os Iteradores ES6. Permite que você obtenha acesso direto a index
/ value
durante a iteração.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Resultado:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Ainda outra abordagem
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
Eu uso o nullhack para esse fim, ele tenta acessar a propriedade de null
, que é um erro:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
throw BREAK
?
Se você deseja manter sua forEach
sintaxe, esta é uma maneira de mantê-la eficiente (embora não tão boa quanto um loop for normal). Verifique imediatamente se há uma variável que saiba se você deseja interromper o loop.
Este exemplo usa uma função anônima para criar um escopo de função em torno do forEach
qual você precisa armazenar as informações concluídas .
(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>
Meus dois centavos.
Eu sei que não é o caminho certo. Não é quebrar o ciclo. É um Jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
Use a array.prototype.every
função, que fornece o utilitário para interromper o loop. Veja o exemplo aqui da documentação Javascript na rede de desenvolvedores Mozilla
Concordo com @bobince, votado.
Além disso, para sua informação:
O Prototype.js tem algo para esse fim:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break
serão capturados e manipulados por Prototype.js internamente, interrompendo o ciclo "cada", mas sem gerar erros externos.
Consulte API Prototype.JS para obter detalhes.
O jQuery também tem uma maneira, basta retornar false no manipulador para interromper o loop mais cedo:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
Consulte a API do jQuery para obter detalhes.
Isso não é o mais eficiente, já que você ainda alterna todos os elementos, mas achei que poderia valer a pena considerar o muito simples:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
continue
é uma palavra-chave, seu código é um erro de sintaxe.
for of
loop e a break;
partir disso, como de costume.
você pode seguir o código abaixo, que funciona para mim:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Eu prefiro 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 da mesma forma forEach
e você pode adicionar a função de retorno para sair dentro. Melhor desempenho também.
Se você precisar quebrar com base no valor dos elementos que já estão em sua matriz, como no seu caso (ou seja, se a condição de interrupção não depender da variável em tempo de execução que pode mudar após a matriz receber seus valores de elemento), você também pode usar a combinação de fatia () e indexOf () seguinte maneira.
Se precisar interromper quando forEach chegar a 'Apple', você pode 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
});
Conforme declarado em W3Schools.com, o método slice () retorna os elementos selecionados em uma matriz, como um novo objeto de matriz. A matriz original não será alterada.
Veja no JSFiddle
Espero que ajude alguém.
Você pode criar uma variante forEach
que permite break
, continue
, return
, e mesmo async
/ await
: (exemplo escrito à máquina)
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];
}
};
Uso:
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);
}
tente com "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" }
Sim, é possível continuar e sair de um loop forEach.
Para continuar, você pode usar return, o loop continuará, mas a função atual terminará.
Para sair do loop, você pode definir o terceiro parâmetro como comprimento 0, definido como matriz vazia. O loop não continua, a função atual continua, então você pode usar "return" para finalizar, como sair de um loop normal para ...
Este:
[1,2,3,4,5,6,7,8,9,10].forEach((a,b,c) => {
console.log(a);
if(b == 2){return;}
if(b == 4){c.length = 0;return;}
console.log("next...",b);
});
imprimirá isto:
1
next... 0
2
next... 1
3
4
next... 3
5
Antes, meu código está abaixo
this.state.itemsDataSource.forEach((item: any) => {
if (!item.isByPass && (item.invoiceDate == null || item.invoiceNumber == 0)) {
return false;
}
});
Eu mudei para abaixo, foi corrigido.
for (var i = 0; i < this.state.itemsDataSource.length; i++) {
var item = this.state.itemsDataSource[i];
if (!item.isByPass && (item.invoiceDate == null || item.invoiceNumber == 0)) {
return false;
}
}
return
fato continue a iteração, pulará qualquer código que vier depois dele no bloco. Tome este código, por exemplo:[1,2,3].forEach(function(el) { if(el === 2) { console.log(`Match on 2!`); return; } console.log(el); });
.Oconsole.log(el);
será ignorado quando 2 corresponder.