cara memecahkan fungsi _.each di underscore.js

200

Saya sedang mencari cara untuk menghentikan iterasi _.each()metode underscore.js , tetapi tidak dapat menemukan solusinya. jQuery .each()dapat rusak jika Anda melakukannya return false.

Apakah ada cara untuk berhenti menggarisbawahi masing-masing ()?

_([1,2,3]).each(function(v){
    if (v==2) return /*what?*/;
})
dy_
sumber
4
Saya rasa itu tidak mungkin, karena forEachfungsi asli tidak menawarkan fitur ini juga.
Felix Kling
8
Biasanya ketika menggunakan eachdengan penutupan (dalam kebanyakan bahasa), Anda ingin memfilter daftar Anda terlebih dahulu. Dengan begitu Anda tidak perlu khawatir untuk tidak melakukannya. Secara umum, jika Anda perlu istirahat lebih awal dari iterasi, mungkin ada cara lain yang bisa Anda lakukan.
Rob Hruska
Berikut adalah beberapa pertanyaan terkait untuk Groovy, di mana perilaku (ketidakmampuan untuk melepaskan diri dari eachpenutupan) mirip dengan JavaScript.
Rob Hruska
@Dmitry_F, seperti yang dicatat orang lain, Anda tidak bisa melakukan persis apa yang Anda minta. Tetapi seperti yang saya tunjukkan, Anda dapat menggunakan Array.everyuntuk meniru perilaku yang Anda inginkan.
aeskr
@Rampok. Bersulang. Komentar pertama sangat membantu. Memang ada cara berbeda yang bisa saya lakukan.
net.uk.sweet

Jawaban:

267

Anda tidak dapat melepaskan diri dari eachmetode — ini mengemulasi forEachperilaku metode asli , dan yang asli forEachtidak menyediakan untuk keluar dari loop (selain melemparkan pengecualian).

Namun, semua harapan tidak hilang! Anda dapat menggunakan Array.everymetode ini. :)

Dari tautan itu:

everymengeksekusi callbackfungsi yang disediakan satu kali untuk setiap elemen yang ada dalam array sampai menemukan satu tempat callbackmengembalikan nilai yang salah. Jika elemen tersebut ditemukan, everymetode segera mengembalikan false.

Dengan kata lain, Anda dapat melakukan sesuatu yang berbelit-belit seperti ini ( tautan ke JSFiddle ):

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

Ini akan mengingatkan 1melalui 3, dan kemudian "pecah" keluar dari loop.

Anda menggunakan underscore.js, sehingga Anda akan senang untuk mengetahui bahwa itu tidak memberikan everymetode-mereka menyebutnya every, tapi sebagai link yang menyebutkan, mereka juga menyediakan sebuah alias yang disebut all.

aeskr
sumber
2
Apakah underscore.js menyediakan implementasi untuk ini juga?
Felix Kling
1
@ Feliksling, ya itu. Saya telah menambahkan itu ke jawaban saya.
aeskr
2
saat ini (20/513), tidak ada metode _.every()atau _.all()metode untuk array dalam garis bawah - jadi tetap gunakan Array.every().
pkyeck
3
Ini akan berhasil, tetapi ini merupakan alasan biasa untuk menggunakan every. Jadi hati-hati untuk keterbacaan.
evanrmurphy
3
Dokumen garis bawah untuk _.each()memiliki catatan khusus tentang fakta bahwa Anda tidak dapat keluar dari loop, dan menyarankan Anda menggunakannya _.find()sebagai gantinya. http://underscorejs.org/#each
blatt
70

Memperbarui:

_.find akan lebih baik karena keluar dari loop ketika elemen ditemukan:

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

** Tua **

Jika Anda ingin melepaskan loop secara kondisional, gunakan _.filter api sebagai ganti _.each. Berikut ini cuplikan kode

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
sumber
1
ini tidak memutus loop - itu hanya menyaring array. bayangkan Anda belum memiliki 2 tetapi 20.000 item dalam array. Anda login hanya akan menghasilkan contoh yang Anda posting tetapi loop akan berjalan 20.000 kali :(
pkyeck
@pkyeck Anda benar, mungkin _.find lebih baik daripada _.filter karena rusak setelah elemnt ditemukan, inilah biola: jsfiddle.net/niki4810/9K3EV
Nikhil
2
Saya pikir jawaban ini harus ditandai sebagai jawaban yang benar. _.findtidak persis apa yang diminta: beralihlah ke daftar sampai panggilan balik kembali true.
Fabien Quatravaux
Dipilih untuk jawaban ini karena jawaban yang diterima (Array.every) tidak akan berfungsi pada objek, tetapi _.find () akan.
matt
Dan itulah yang direkomendasikan dalam dokumen: Ini juga baik untuk dicatat bahwa setiap loop tidak dapat diputus - untuk istirahat, gunakan _.find sebagai gantinya.
shaharsol
15

Anda bisa melihat-lihat ke _.somebukannya _.each. _.someberhenti melintasi daftar setelah predikat benar. Hasil dapat disimpan dalam variabel eksternal.

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

Lihat http://underscorejs.org/#some

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

Mungkin Anda ingin Underscore's any () atau find (), yang akan berhenti memproses ketika suatu kondisi terpenuhi.

Grantwparks
sumber
3

Seperti jawaban lainnya, itu tidak mungkin. Berikut adalah komentar tentang pemutus dalam isu garis bawah menggarisbawahi # 21

czizzy
sumber
3

Anda tidak dapat memecah forEachdalam garis bawah, karena mengemulasi perilaku asli EcmaScript 5.

JaredMcAteer
sumber
2

Saya percaya jika array Anda sebenarnya adalah objek, Anda dapat kembali menggunakan objek kosong.

_.({1,2,3,4,5}).each(function(v){  
  if(v===3) return {}; 
});
bm_i
sumber
Itu hanya terjadi dengan EcmaScript v <5 sebagai perbandingan yang menggarisbawahi tidak untuk memeriksa apakah Anda mengembalikan objek kosong di alternatif yang disediakan untuk forEach hanya dilakukan ketika yang asli tidak tersedia.
Alfonso de la Osa
1

Memperbarui:

Anda benar-benar dapat "memecahkan" dengan melemparkan kesalahan di dalam dan menangkapnya di luar: sesuatu seperti ini:

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

Ini jelas memiliki beberapa implikasi mengenai pengecualian lain yang dipicu oleh kode Anda dalam loop, jadi gunakan dengan hati-hati!

bm_i
sumber
Senang bagaimana saya mendapatkan begitu banyak suara untuk ini, dan orang ini mendapat banyak up untuk stackoverflow.com/a/2641374/674720
bm_i
1
Saya terlambat ke pesta tetapi perhatikan bahwa pria tidak hanya mengatakan apa yang Anda sarankan, tetapi menawarkan dua alternatif lagi (dan lebih cocok). Satu-satunya yang menawarkan "retas" kalau-kalau pengguna menginginkannya. Anda malah hanya menawarkan hack jelek.
Areks
0

bekerja dalam kasus saya

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