como quebrar a função _.each em underscore.js

200

Estou procurando uma maneira de parar as iterações do _.each()método underscore.js , mas não consigo encontrar a solução. O jQuery .each()pode quebrar se você o fizer return false.

Existe uma maneira de parar de sublinhar cada ()?

_([1,2,3]).each(function(v){
    if (v==2) return /*what?*/;
})
dy_
fonte
4
Eu não acho que é possível, porque a forEachfunção nativa também não oferece esse recurso.
Felix Kling
8
Normalmente, ao usar eachum fechamento (na maioria dos idiomas), você deseja filtrar sua lista primeiro. Dessa forma, você não precisa se preocupar em romper com isso. De um modo geral, se você precisar interromper antecipadamente uma iteração, provavelmente há uma maneira diferente de fazê-lo.
Rob Hruska
Aqui estão algumas perguntas relacionadas ao Groovy, nas quais o comportamento (incapacidade de interromper convenientemente um eachfechamento) é semelhante ao JavaScript.
Rob Hruska
@Dmitry_F, como outros observaram, você não pode fazer exatamente o que está pedindo. Mas, como demonstrei, você pode Array.everyemular o comportamento que deseja.
aeskr
@Roubar. Felicidades. Primeiro comentário realmente útil. De fato, havia uma maneira diferente de fazer isso.
net.uk.sweet

Respostas:

267

Você não pode interromper o eachmétodo - ele simula o forEachcomportamento do método nativo , e o nativo forEachnão fornece para escapar do loop (exceto para lançar uma exceção).

No entanto, toda a esperança não está perdida! Você pode usar o Array.everymétodo :)

Nesse link:

everyexecuta a callbackfunção fornecida uma vez para cada elemento presente na matriz até encontrar uma ondecallback retorne um valor falso. Se esse elemento for encontrado, o everymétodo retornará imediatamente false.

Em outras palavras, você poderia fazer algo complicado como este ( link para o JSFiddle ):

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

Isso alertará 1 através de 3, em seguida, "quebrar" fora do circuito.

Você está usando underscore.js, assim você ficará contente em saber que ele não fornecer um everymétodo que eles chamam every, mas como que apontam menciona, eles também fornecem um alias chamado all.

aeskr
fonte
2
O underscore.js também fornece uma implementação para isso?
Felix Kling
1
@FelixKling, sim, sim. Eu adicionei isso à minha resposta.
aeskr
2
No momento (05/2013), não existe _.every()nem um _.all()método para matrizes em sublinhado - portanto, atenha-se a Array.every().
Pkyeck # 9/13
3
Isso funcionará, mas é uma razão usual para o uso every. Portanto, cuidado com a legibilidade.
evanrmurphy
3
Os documentos de sublinhado para _.each()têm uma observação específica sobre o fato de que você não pode sair do loop e recomenda o uso _.find(). http://underscorejs.org/#each
blatt
70

Atualizar:

_.find seria melhor, pois ele sai do loop quando o elemento é encontrado:

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var count = 0;
var filteredEl = _.find(searchArr,function(arrEl){ 
              count = count +1;
              if(arrEl.id === 1 ){
                  return arrEl;
              }
            });

console.log(filteredEl);
//since we are searching the first element in the array, the count will be one
console.log(count);
//output: filteredEl : {id:1,text:"foo"} , count: 1

** Velho **

Se você deseja interromper condicionalmente um loop, use _.filter api em vez de _.each. Aqui está um trecho de código

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var filteredEl = _.filter(searchArr,function(arrEl){ 
                  if(arrEl.id === 1 ){
                      return arrEl;
                  }
                });
console.log(filteredEl);
//output: {id:1,text:"foo"}
Nikhil
fonte
1
isso não quebra o loop - apenas filtra a matriz. imagine que você não tenha 2, mas 20.000 itens na matriz. o log mostraria apenas o exemplo que você postou, mas o loop seria executado 20.000 vezes :(
pkyeck
@pkyeck você está certo, pode ser _.find é melhor do que _.filter como quebra após o elemnt for encontrado, aqui é o violino: jsfiddle.net/niki4810/9K3EV
Nikhil
2
Eu acho que essa resposta deve ser marcada como a correta. _.findfaz exatamente o que é solicitado: itere na lista até o retorno da chamada true.
Fabien Quatravaux
Votou para esta resposta porque a resposta aceita (Array.every) não funcionará em objetos, mas _.find () funcionará.
Matt
E é isso que é recomendado nos documentos: Também é bom observar que cada loop não pode ser quebrado - para quebrar, use _.find.
shaharsol
15

Você pode dar uma olhada em _.somevez de _.each. _.somepára de percorrer a lista quando um predicado for verdadeiro. Os resultados podem ser armazenados em uma variável externa.

_.some([1, 2, 3], function(v) {
    if (v == 2) return true;
})

Veja http://underscorejs.org/#some

Joan
fonte
6
_([1,2,3]).find(function(v){
    return v if (v==2);
})
Rockyboy_ruby
fonte
3

Talvez você queira Underscore's any () ou find (), que interromperão o processamento quando uma condição for atendida.

grantwparks
fonte
3

Como as outras respostas, é impossível. Aqui está o comentário sobre o disjuntor na questão de sublinhado de sublinhado # 21

czizzy
fonte
3

Você não pode quebrar um forEachsublinhado, pois emula o comportamento nativo do EcmaScript 5.

JaredMcAteer
fonte
2

Acredito que se sua matriz era realmente um objeto, você poderia retornar usando um objeto vazio.

_.({1,2,3,4,5}).each(function(v){  
  if(v===3) return {}; 
});
bm_i
fonte
Isso acontece apenas com o EcmaScript v <5, pois a comparação sublinhada faz para verificar se você está retornando o objeto vazio na alternativa fornecida ao forEach, apenas quando o nativo não está disponível.
Alfonso de la Osa
1

Atualizar:

Você pode realmente "quebrar" lançando um erro dentro e capturando-o do lado de fora: algo como isto:

try{
  _([1,2,3]).each(function(v){
    if (v==2) throw new Error('break');
  });
}catch(e){
  if(e.message === 'break'){
    //break successful
  }
}

Obviamente, isso tem algumas implicações em relação a outras exceções que seu código aciona no loop, portanto, use com cuidado!

bm_i
fonte
Amor como eu fico tantos votos para baixo para isso, e esse cara recebe toda uma carga de ups para seu stackoverflow.com/a/2641374/674720
bm_i
1
Estou atrasado para a festa, mas observe que o cara não apenas disse o que você sugeriu, mas ofereceu mais duas alternativas (e mais adequadas). O único ofereceu o "hack" no caso de o usuário, por todos os meios, querer. Você apenas ofereceu o truque feio.
Areks
0

trabalhou no meu caso

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
aleXela
fonte