come interrompere la funzione _.each in underscore.js


200

Sto cercando un modo per interrompere le iterazioni del _.each()metodo underscore.js , ma non riesco a trovare la soluzione. jQuery .each()può rompersi se lo fai return false.

C'è un modo per smettere di sottolineare ciascuna ()?

_([1,2,3]).each(function(v){
    if (v==2) return /*what?*/;
})

4
Non credo sia possibile, perché la forEachfunzione nativa non offre questa funzione.
Felix Kling

8
Normalmente quando si utilizza eachcon una chiusura (nella maggior parte delle lingue), si desidera prima filtrare l'elenco. In questo modo non devi preoccuparti di rompere da esso. In generale, se hai bisogno di uscire presto da un'iterazione, probabilmente c'è un modo diverso in cui potresti farlo.
Rob Hruska,

Ecco un paio di domande relative a Groovy, in cui il comportamento (incapacità di rompere convenientemente da una eachchiusura) è simile a JavaScript.
Rob Hruska,

@Dmitry_F, come altri hanno notato, non puoi fare esattamente quello che stai chiedendo. Ma come ho dimostrato, puoi usare Array.everyper emulare il comportamento che desideri.
aeskr

@Rapinare. Saluti. Primo commento davvero utile. In effetti c'era un modo diverso in cui avrei potuto farlo.
net.uk.sweet

Risposte:


267

Non puoi interrompere il eachmetodo: emula il forEachcomportamento del metodo nativo e il nativo forEachnon provvede a sfuggire al ciclo (oltre a generare un'eccezione).

Tuttavia, ogni speranza non è persa! Puoi usare ilArray.every metodo :)

Da quel link:

everyesegue callbackuna volta la funzione fornita per ciascun elemento presente nella matrice fino a quando non ne trova una in cui callbackrestituisce un valore falso. Se viene trovato un tale elemento, il everymetodo restituisce immediatamente falso.

In altre parole, potresti fare qualcosa di contorto come questo ( link a JSFiddle ):

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

Questo avviserà 1attraverso 3, e poi "rompere" fuori dal giro.

Stai usando underscore.js, in modo da sarete contenti di sapere che essa non fornisce un everymetodo-lo chiamano every, ma come quel link menziona, ma anche fornire un alias chiamato all.


2
Underscore.js fornisce un'implementazione anche per questo?
Felix Kling

1
@FelixKling, sì, lo fa. L'ho aggiunto alla mia risposta.
aeskr

2
in questo momento (05/2013), non esiste _.every()né un _.all()metodo né un metodo per le matrici di sottolineatura, quindi attenersi a Array.every().
becco

3
Funzionerà, ma è un motivo normale per l'utilizzo every. Quindi attenzione per la leggibilità.
evanrmurphy,

3
Il carattere di sottolineatura per _.each()ha una nota specifica sul fatto che non è possibile uscire dal ciclo e consiglia di utilizzare _.find()invece. http://underscorejs.org/#each
blatt

70

Aggiornare:

_.find sarebbe meglio in quanto esce dal ciclo quando viene trovato l'elemento:

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

** Vecchio **

Se vuoi uscire condizionatamente da un ciclo, usa _.filter api invece di _.each. Ecco uno snippet di codice

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

1
questo non interrompe il ciclo, ma filtra solo l'array. immagina di non avere 2 ma 20.000 articoli nell'array. il tuo log genererebbe solo l'esempio che hai postato ma il loop verrebbe eseguito 20.000 volte :(
pkyeck

@pkyeck hai ragione, potrebbe essere _.find è meglio di _.filter in quanto si rompe dopo che è stato trovato l'elemnt, ecco il violino: jsfiddle.net/niki4810/9K3EV
Nikhil

2
Penso che questa risposta dovrebbe essere contrassegnata come quella corretta. _.findfa esattamente ciò che viene chiesto: scorrere l'elenco fino a quando non viene restituito il callback true.
Fabien Quatravaux,

Votato per questa risposta perché la risposta accettata (Array.every) non funzionerà sugli oggetti, ma _.find () lo farà.
matt

Ed è quello che è raccomandato nei documenti: è anche bene notare che non è possibile spezzare un ciclo - per interrompere, usa invece _.find.
Shaharsol,

15

Puoi dare un'occhiata a _.someinvece di _.each. _.somesmette di attraversare l'elenco una volta che un predicato è vero. I risultati possono essere memorizzati in una variabile esterna.

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

Vedi http://underscorejs.org/#some



3

Forse vuoi Underscore's any () o find (), che interromperà l'elaborazione quando viene soddisfatta una condizione.



3

Non è possibile rompere un carattere forEachdi sottolineatura in, poiché emula il comportamento nativo di EcmaScript 5.


2

Credo che se il tuo array fosse effettivamente un oggetto che potresti restituire usando un oggetto vuoto.

_.({1,2,3,4,5}).each(function(v){  
  if(v===3) return {}; 
});

Ciò accade solo con EcmaScript v <5 poiché il confronto che il carattere di sottolineatura esegue per verificare se si sta restituendo l'oggetto vuoto nell'alternativa fornita a forOach viene eseguito solo quando quello nativo non è disponibile.
Alfonso de la Osa,


1

Aggiornare:

Puoi effettivamente "rompere" lanciando un errore all'interno e catturandolo all'esterno: qualcosa del genere:

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

Questo ovviamente ha alcune implicazioni per quanto riguarda eventuali altre eccezioni che il tuo codice attiva nel ciclo, quindi usa con cautela!


Amore come ottenere così tanti voti verso il basso per questo, e questo ragazzo ottiene un intero carico di alti per il suo stackoverflow.com/a/2641374/674720
bm_i

1
Sono in ritardo alla festa, ma nota che il ragazzo non solo ha detto quello che mi hai suggerito, ma ha offerto altre due alternative (e più adatte). L'unico ha offerto il "hack" nel caso in cui l'utente lo desideri. Invece hai offerto solo il brutto hack.
Areks,

0

ha funzionato nel mio caso

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.