วิธีทำลายฟังก์ชัน _.each ใน underscore.js


200

ฉันกำลังมองหาวิธีที่จะหยุดการทำซ้ำของ underscore.js _.each()วิธี แต่ไม่สามารถหาวิธีแก้ปัญหา jQuery สามารถทำลายถ้าคุณทำ.each()return false

มีวิธีหยุดขีดเส้นใต้แต่ละอัน () หรือไม่?

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

4
ฉันไม่คิดว่าเป็นไปได้เพราะforEachฟังก์ชั่นพื้นฐานไม่ได้เสนอคุณสมบัตินี้เช่นกัน
เฟลิกซ์ลิ่ง

8
โดยปกติเมื่อใช้eachกับการปิด (ในภาษาส่วนใหญ่) คุณต้องการกรองรายการของคุณก่อน ด้วยวิธีนี้คุณไม่ต้องกังวลกับการแตกหัก โดยทั่วไปแล้วหากคุณต้องการหยุดยั้งตั้งแต่ต้นซ้ำอาจมีวิธีอื่นที่คุณสามารถทำได้
Rob Hruska

ต่อไปนี้ เป็นคำถามที่เกี่ยวข้องกับ Groovy ซึ่งพฤติกรรม (ไม่สามารถแยกจากการeachปิดได้อย่างสะดวก) คล้ายกับ JavaScript
Rob Hruska

@Dmitry_F ตามที่คนอื่น ๆ สังเกตคุณไม่สามารถทำสิ่งที่คุณขอได้อย่างแน่นอน แต่เมื่อฉันสาธิตคุณสามารถใช้Array.everyเพื่อเลียนแบบพฤติกรรมที่คุณต้องการ
aeskr

@ปล้น. ไชโย ความคิดเห็นแรกที่เป็นประโยชน์จริงๆ แน่นอนว่ามีวิธีอื่นที่ฉันสามารถทำได้
net.uk.sweet

คำตอบ:


267

คุณไม่สามารถหยุดจากeachเมธอดได้ - มันเลียนแบบforEachพฤติกรรมของเมธอดดั้งเดิมและเนทีฟforEachไม่ได้ให้การหลบหนีลูป (นอกเหนือจากการโยนข้อยกเว้น)

อย่างไรก็ตามความหวังทั้งหมดจะไม่สูญหายไป! คุณสามารถใช้Array.everyวิธีการ :)

จากลิงค์นั้น:

everyดำเนินการcallbackฟังก์ชั่นที่มีให้หนึ่งครั้งสำหรับแต่ละองค์ประกอบที่มีอยู่ในอาร์เรย์จนกว่าจะพบหนึ่งที่callbackส่งกลับค่าเท็จ หากพบองค์ประกอบดังกล่าวeveryเมธอดจะส่งคืน false ทันที

กล่าวอีกนัยหนึ่งคุณสามารถทำสิ่งที่ซับซ้อนเช่นนี้ ( ลิงก์ไปยัง JSFiddle ):

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

สิ่งนี้จะเตือน1ผ่าน3แล้ว "แยก" ออกจากลูป

คุณกำลังใช้ underscore.js ดังนั้นคุณจะยินดีที่จะเรียนรู้ว่ามันไม่ให้everyวิธีการพวกเขาเรียกมันว่าแต่เป็นลิงค์ที่ระบุว่าพวกเขายังให้สมญานามที่เรียกว่าeveryall


2
underscore.js มีการใช้งานสำหรับสิ่งนี้ด้วยหรือไม่
เฟลิกซ์ลิ่ง

1
@ FelixKling ใช่ใช่ ฉันได้เพิ่มเข้าไปในคำตอบของฉัน
aeskr

2
ในขณะนี้ (05/2013) มีไม่เป็น_.every()หรือมิได้_.all()วิธีการอาร์เรย์ในขีด - Array.every()เพื่อให้ติดกับ
pkyeck

3
นี้จะทำงาน everyแต่มันเป็นเหตุผลที่ปกติสำหรับการใช้ ดังนั้นระวังการอ่าน
evanrmurphy

3
เอกสารขีดเส้นใต้สำหรับ_.each()มีหมายเหตุเฉพาะเกี่ยวกับข้อเท็จจริงที่ว่าคุณไม่สามารถแยกจากลูปและแนะนำให้คุณใช้_.find()แทน http://underscorejs.org/#each
blatt

70

ปรับปรุง:

_.find จะดีกว่าเมื่อแยกออกจากลูปเมื่อองค์ประกอบพบ:

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

** เก่า **

หากคุณต้องการแยกลูปแบบมีเงื่อนไขให้ใช้ _.filter api แทน _.each นี่คือข้อมูลโค้ด

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
สิ่งนี้ไม่ทำลายลูป - เพียงแค่กรองอาร์เรย์ ลองนึกภาพคุณมีไม่ 2 แต่ 20,000 รายการในอาร์เรย์ คุณเข้าสู่ระบบเท่านั้นที่จะส่งออกตัวอย่างที่คุณโพสต์ แต่วงจะทำงาน 20.000 ครั้ง :(
pkyeck

@peckeck คุณพูดถูกอาจเป็น _.find ดีกว่า _.filter เมื่อพบ elemnt นี่คือซอ: jsfiddle.net/niki4810/9K3EV
Nikhil

2
ฉันคิดว่าคำตอบนี้ควรทำเครื่องหมายว่าถูกต้อง _.findทำสิ่งที่ถูกถามอย่างแน่นอน: วนซ้ำในรายการจนกว่าการโทรกลับจะกลับtrueมา
Fabien Quatravaux

โหวตให้กับคำตอบนี้เนื่องจากคำตอบที่ยอมรับ (Array.every) จะไม่ทำงานกับวัตถุ แต่ _.find () จะ
แมตต์

และนั่นคือสิ่งที่แนะนำในเอกสาร: นอกจากนี้ยังควรทราบว่าแต่ละวงไม่สามารถแยกออกจาก - เพื่อแยกให้ใช้ _.find แทน
shaharsol

15

คุณสามารถมีดูมาแทน _.some หยุดการข้ามผ่านรายการเมื่อเพรดิเคตเป็นจริง สามารถเก็บผลลัพธ์ไว้ในตัวแปรภายนอกได้_.each_.some

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

ดูhttp://underscorejs.org/#some



3

บางทีคุณอาจต้องการขีดเส้นใต้ใด ๆ () หรือ find () ซึ่งจะหยุดการประมวลผลเมื่อตรงตามเงื่อนไข



3

คุณไม่สามารถหยุดการforEachขีดเส้นใต้ได้เนื่องจากมันจำลองพฤติกรรมดั้งเดิมของ EcmaScript 5


2

ฉันเชื่อว่าอาร์เรย์ของคุณเป็นวัตถุจริงหรือไม่คุณสามารถกลับมาใช้วัตถุที่ว่างเปล่าได้

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

สิ่งนี้เกิดขึ้นกับ EcmaScript v <5 เป็นการเปรียบเทียบที่ขีดล่างเพื่อตรวจสอบว่าคุณกำลังส่งคืนวัตถุว่างเปล่าในทางเลือกที่ให้ไว้กับ forEach นั้นจะทำก็ต่อเมื่อไม่มีการใช้งานดั้งเดิม
Alfonso de la Osa


1

ปรับปรุง:

คุณสามารถ "ทำลาย" โดยการโยนข้อผิดพลาดเข้าไปข้างในแล้วจับมันข้างนอก: อะไรแบบนี้:

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

เห็นได้ชัดว่าสิ่งนี้มีความหมายบางอย่างเกี่ยวกับข้อยกเว้นอื่น ๆ ที่รหัสของคุณเรียกใช้ในลูปดังนั้นใช้ด้วยความระมัดระวัง!


รักที่ฉันได้รับคะแนนโหวตลงมากมายสำหรับสิ่งนี้และผู้ชายคนนี้ได้รับป๊จำนวนมากสำหรับstackoverflow.com/a/2641374/674720
bm_i

1
ฉันไปงานปาร์ตี้ช้า แต่ให้สังเกตว่าผู้ชายไม่เพียง แต่พูดในสิ่งที่คุณแนะนำ แต่เสนอทางเลือกอีกสองทาง (และเหมาะสมกว่า) เสนอเพียง "แฮ็ค" ในกรณีที่ผู้ใช้ทุกคนต้องการมัน คุณเสนอแฮ็กที่น่าเกลียดแทนเท่านั้น
Areks

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.