Array ลัดวงจรเช่นกัน


1569
[1,2,3].forEach(function(el) {
    if(el === 1) break;
});

ฉันจะทำสิ่งนี้โดยใช้forEachวิธีการใหม่ใน JavaScript ได้อย่างไร ฉันได้พยายามreturn;, และreturn false; ขัดข้องและไม่ทำอะไรเลยนอกจากทำซ้ำอีกครั้งbreakbreakreturn


6
เป็นที่น่าสังเกตว่าในขณะที่returnยังคงทำซ้ำอย่างแน่นอนมันจะข้ามรหัสใด ๆ ที่มาหลังจากนั้นในบล็อก ใช้รหัสนี้เช่น: [1,2,3].forEach(function(el) { if(el === 2) { console.log(`Match on 2!`); return; } console.log(el); });. console.log(el);จะถูกข้ามเมื่อจับคู่ 2
เชน

5
TL; DR:ฉันจะช่วยให้คุณประหยัดเวลาได้มาก ฉันใช้ JS บ่อยมากเมื่อเร็ว ๆ นี้ คำตอบ (จาก 28 ... ) ที่คุณอาจกำลังมองหาคืออันนี้: stackoverflow.com/a/32101207/1599699
Andrew

คำตอบ:


2141

มีของในตัวไม่มีความสามารถในการในbreak forEachในการขัดจังหวะการทำงานคุณจะต้องทำการยกเว้นบางอย่าง เช่น.

var BreakException = {};

try {
  [1, 2, 3].forEach(function(el) {
    console.log(el);
    if (el === 2) throw BreakException;
  });
} catch (e) {
  if (e !== BreakException) throw e;
}

ข้อยกเว้น JavaScript ไม่สวยมาก การforวนซ้ำแบบดั้งเดิมอาจเหมาะสมกว่าหากคุณจำเป็นต้องbreakอยู่ภายใน

ใช้ Array#some

ให้ใช้Array#some:

[1, 2, 3].some(function(el) {
  console.log(el);
  return el === 2;
});

ใช้งานได้เพราะsomeส่งคืนtrueทันทีที่มีการเรียกกลับใด ๆ ดำเนินการในลำดับของอาร์เรย์ส่งคืนtrueทำให้การดำเนินการส่วนที่เหลือลัดวงจร

someผกผันของมันevery(ซึ่งจะหยุดบนreturn false) และforEachวิธีการ ECMAScript ฉบับที่ห้าทั้งหมดซึ่งจะต้องมีการเพิ่มให้กับArray.prototypeเบราว์เซอร์ที่พวกเขากำลังขาดหายไป


110
นี่ไม่สามารถอ่านได้มากกว่าหรือมีประสิทธิภาพมากกว่าการใช้ลูปปกติสำหรับลูป คำตอบควรเป็น "อย่าใช้สำหรับแต่ละกรณี" -1
BT

37
ฉันคิดว่า "บางคน" ใช้ได้ที่นี่ทำไมไม่ลองใช้การเพิ่มประสิทธิภาพทางออกต้น
chrismarx

28
ขอบคุณสำหรับความคิดsomeและeveryสิ่งนี้ควรอยู่ที่ TOP ในคำตอบ ไม่สามารถเข้าใจได้ว่าทำไมคนคิดว่าอ่านน้อย มันยอดเยี่ยมมาก!
Karl Adler

9
การใช้งานArray#someเป็นสิ่งที่ดีจริงๆ ประการแรกมันเข้ากันได้กับเบราว์เซอร์ส่วนใหญ่รวมถึง ie9 และ firefox 1.5 ก็ใช้งานได้ดีเช่นกัน ตัวอย่างกรณีการใช้งานของฉันจะค้นหาดัชนีในอาร์เรย์ของช่วง [a, b] โดยที่ตัวเลขนั้นอยู่ระหว่างขอบเขตล่างและคู่บนขอบเขตทดสอบและส่งกลับค่าจริงเมื่อพบ for..ofจะเป็นทางออกที่ดีที่สุดต่อไปสำหรับเบราว์เซอร์รุ่นใหม่เท่านั้น
Sojimaxi

95
การจัดการข้อยกเว้นไม่ควรใช้เป็นโฟลว์ควบคุม ระยะเวลา
ตรงไปตรงมา

479

ขณะนี้เป็นวิธีที่ดียิ่งขึ้นที่จะทำเช่นนี้ใน ECMAScript2015 (aka ES6) โดยใช้ใหม่สำหรับของวง ตัวอย่างเช่นรหัสนี้จะไม่พิมพ์องค์ประกอบอาร์เรย์หลังจากหมายเลข 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;
  }
}

จากเอกสาร:

ทั้งสำหรับ ... ในและสำหรับ ... ของคำสั่งซ้ำมากกว่าบางสิ่งบางอย่าง ความแตกต่างที่สำคัญระหว่างพวกเขาคือสิ่งที่พวกเขาย้ำ สำหรับ ... ในคำสั่ง iterates กว่าคุณสมบัติที่นับของวัตถุในการสั่งซื้อแทรกเดิม สำหรับ ... ของคำสั่ง iterates มากกว่าข้อมูลที่กำหนดวัตถุ iterable ที่จะซ้ำมากกว่า

ต้องการดัชนีในการวนซ้ำหรือไม่? คุณสามารถใช้Array.entries():

for (const [index, el] of arr.entries()) {
  if ( index === 5 ) break;
}

4
@superhero คุณจะได้รับดัชนีขององค์ประกอบในสำหรับ ... entriesของวงคุณเพียงแค่ต้องใช้ สำหรับ (const [ดัชนีองค์ประกอบ] ของ someArray.entries ()) {// ... }
blackxored

ไม่แนะนำให้ใช้สำหรับ ... ในกับอาร์เรย์ใช่ไหม
schehata

4
@emostafa คุณถูกต้องเกี่ยวกับในลูปไม่ได้ถูกแนะนำสำหรับอาร์เรย์ แต่นี้เป็นวิธีการที่ใช้จริงสำหรับของวง
canac

นี่คือ "สำหรับ" และนี่เป็นโซลูชันที่สะอาดหมดจดจริงๆ ... แต่นี่ก็เป็นคุณลักษณะ ES6 ดังนั้นโปรดทราบว่านี่จะใช้งานได้ต่อเมื่อสภาพแวดล้อมของคุณตั้งค่าสำหรับ ES6
ชาด

ฉันพบว่าตัวเองใช้โซลูชันนี้มากและฉันก็ใช้มันเพื่อวัตถุเช่นกัน ด้วยวัตถุคุณสามารถทำObject.entries(myObject)และใช้มันเหมือนกับที่คุณใช้for..inสำหรับอาร์เรย์ โปรดทราบว่าอาร์เรย์ JS นั้นเป็นวัตถุภายใต้ประทุน: blog.niftysnippets.org/2011/01/myth-of-arrays.html
แอนดรูว์

204

คุณสามารถใช้ทุกวิธี:

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

ES6

[1,2,3].every( el => el !== 1 )

สำหรับการสนับสนุนเบราว์เซอร์เก่าใช้:

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

รายละเอียดเพิ่มเติมที่นี่


10
ดีและสะอาดใน ES6 ตอนนี้ -[1,2,3].every( el => el !== 1 )
metame

1
@Valdemar แต่ไม่every รับประกันว่าจะโทรออกตามลำดับ?
Pacerier

4
@Pacerier คุณสามารถดูอัลกอริทึมในข้อกำหนด ES6 ที่ดัชนีkเริ่มต้นที่ 0 และเพิ่มขึ้น 1: http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.every
XP1

@ XP1, ผู้ดำเนินการทั้งหมดจำเป็นต้องทำเช่นนั้นหรือไม่?
Pacerier

1
@Pierier, การใช้งานที่ได้รับความนิยมส่วนใหญ่ทำงานอย่างถูกต้อง หากคุณกังวลเกี่ยวกับการใช้งานแบบฝังตัวโดยปกติจะเป็น Opera หรือ webkit วิธีที่ทุกคนเรียก callbackfn หนึ่งครั้งสำหรับแต่ละองค์ประกอบที่มีอยู่ในอาร์เรย์ตามลำดับจากน้อยไปหามากจนพบสิ่งที่ callbackfn ส่งกลับค่าเท็จ ดูที่ขั้นตอนที่ 7 ให้ k เป็น 0 และ 8.e เพิ่ม k ด้วย 1
Valdemar_Rudolfovich

78

การอ้างอิงจากเอกสาร MDN ของArray.prototype.forEach() :

มีวิธีที่จะหยุดหรือทำลายไม่มีforEach()ห่วงนอกเหนือจากการขว้างปายกเว้น หากคุณต้องการพฤติกรรมดังกล่าว.forEach()วิธีการนี้เป็นเครื่องมือที่ผิดให้ใช้การวนซ้ำธรรมดาแทน หากคุณกำลังทดสอบองค์ประกอบอาร์เรย์สำหรับเพรดิเคตและต้องการค่าบูลีนส่งคืนคุณสามารถใช้every()หรือsome()แทน

สำหรับรหัสของคุณ (ในคำถาม) ตามที่ @bobince แนะนำให้ใช้Array.prototype.some()แทน มันเหมาะกับกรณีของคุณ

Array.prototype.some()ดำเนินการฟังก์ชั่นการโทรกลับครั้งเดียวสำหรับแต่ละองค์ประกอบที่มีอยู่ในอาร์เรย์จนกว่าจะพบหนึ่งที่โทรกลับส่งกลับค่าความจริง (ค่าที่กลายเป็นจริงเมื่อถูกแปลงเป็นBoolean) หากพบองค์ประกอบดังกล่าวจะsome()ส่งกลับค่าความจริงทันที มิฉะนั้นsome()ส่งคืนเท็จ การเรียกกลับถูกเรียกใช้เฉพาะสำหรับดัชนีของอาร์เรย์ที่มีค่าที่กำหนดไว้เท่านั้น มันไม่ได้ถูกเรียกใช้สำหรับดัชนีที่ถูกลบหรือที่ไม่เคยมีการกำหนดค่า


1
นี่คือคำตอบที่ถูกต้อง 'บาง' ทำในสิ่งที่ foreach / break จะทำ มันวนซ้ำจนกว่าการวนซ้ำ n = จริง
แอนโทนีบูธ

74

forEachแต่น่าเสียดายที่ในกรณีนี้มันจะดีมากถ้าคุณไม่ได้ใช้งาน แทนที่จะใช้การforวนซ้ำปกติและตอนนี้มันจะทำงานตรงตามที่คุณคาดไว้

var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
  if (array[i] === 1){
    break;
  }
}

27
มันทำให้ฉันตกใจว่าการโหวตสูงสุดเป็นการดำเนินการที่เลวร้ายที่สุดเท่าที่จะเป็นไปได้เมื่อเทียบกับประสิทธิภาพที่สูงขึ้นโค้ดที่น้อยลงและการอ่านที่ดีขึ้นของคำตอบที่ถูกต้องนี้ โยนข้อยกเว้น ... จริงเหรอ? เป็นแบบดั้งเดิมสำหรับการวนรอบไม่ kewl เพียงพอหรือไม่
gdbj

2
@ gdbj ฉันเห็นด้วยกับคำสั่งของคุณและใช้วิธีการนี้ แต่สิ่งที่ทำให้ฉันตกใจจริงๆคือไม่มีทางที่จะออกจาก forEach โดยที่ไม่มีแฮ็คเหล่านี้ตอนนี้มันออกแบบไม่ดี
ScottN

28

พิจารณาที่จะใช้jquery's eachวิธีเพราะมันจะช่วยให้การกลับมาฟังก์ชั่นภายในเรียกกลับเท็จ

$.each(function(e, i) { 
   if (i % 2) return false;
   console.log(e)
})

ห้องสมุด Lodash ยังมีtakeWhileวิธีการที่สามารถโยงกับแผนที่ / ลด / พับ ฯลฯ :

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');
// => []

1
เหตุผลที่ดีในการใช้ jQuery forEavascript จาวาสคริปต์แต่ละภาษายังขาดอยู่
Alex Grande

3
@AlexGrande jQuery's forEach และ JavaScript ของ forEach ไม่สามารถทำงานร่วมกันได้
Bjorn

10
มีการใช้ JavaScript ในหลาย ๆ ที่ jQuery ไม่ใช่ตัวเลือก
JBRWilkinson


18

หากคุณต้องการใช้คำแนะนำของ Dean Edwardและโยนข้อผิดพลาด StopIteration เพื่อแยกวงโดยไม่ต้องจับข้อผิดพลาดคุณสามารถใช้ฟังก์ชันต่อไปนี้ ( แต่เดิมจากที่นี่ ):

// 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;
        }
      }
    };
  }
})();

โค้ดด้านบนจะให้ความสามารถในการเรียกใช้โค้ดดังต่อไปนี้โดยไม่ต้องทำคำสั่ง 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);
});

สิ่งสำคัญที่ต้องจำคือว่าสิ่งนี้จะอัปเดตฟังก์ชัน Array.prototype.forEach เท่านั้นหากมีอยู่แล้ว หากไม่มีอยู่แล้วจะไม่แก้ไข


11

คำตอบสั้น ๆ ใช้งาน: ใช้สำหรับการนี้หรือเปลี่ยนรหัสของคุณเพื่อหลีกเลี่ยงการทำลายของfor...break forEachไม่ได้ใช้.some()หรือจะเลียนแบบ.every() for...breakเขียนโค้ดของคุณเพื่อหลีกเลี่ยงการห่วงหรือการใช้งานfor...break for...breakทุกครั้งที่คุณใช้วิธีการเหล่านี้เป็นfor...breakทางเลือกที่พระเจ้าฆ่าลูกแมว

คำตอบยาว:

.some()และ.every()ทั้งสองคืนbooleanค่า.some()ส่งกลับtrueถ้ามีองค์ประกอบใด ๆ ที่ส่งกลับฟังก์ชั่นกลับtrueมาทุกคืนfalseถ้ามีองค์ประกอบใด ๆ ที่ส่งกลับฟังก์ชั่นfalseที่ผ่านการกลับมาทำงาน นี่คือความหมายของฟังก์ชั่น การใช้ฟังก์ชั่นสำหรับสิ่งที่พวกเขาไม่ได้แปลว่าแย่ลงมากแล้วใช้ตารางสำหรับการจัดวางแทน CSS เพราะมันทำให้ทุกคนที่อ่านโค้ดของคุณหงุดหงิด

นอกจากนี้ทางเป็นไปได้ที่จะใช้วิธีการเหล่านี้เป็นfor...breakทางเลือกที่จะทำให้เกิดผลข้างเคียง (เปลี่ยนบาง vars ด้านนอกของ.some()ฟังก์ชั่นการโทรกลับ) for...breakและนี่คือไม่มากแตกต่างจาก

ดังนั้นการใช้.some()หรือ.every()เป็นfor...breakทางเลือกแบบลูปจึงไม่มีผลข้างเคียงนี่ไม่สะอาดเท่านี้for...breakกว่านี้มันน่าหงุดหงิดดังนั้นมันจึงไม่ดีกว่า

คุณสามารถเขียนโค้ดของคุณใหม่ได้ตลอดเวลาเพื่อไม่จำเป็นต้องfor...breakใช้ คุณสามารถกรองอาเรย์โดยใช้.filter()คุณสามารถแยกอาเรย์โดยใช้.slice()และจากนั้นใช้.forEach()หรือ.map()เป็นส่วนหนึ่งของอาเรย์


การใช้. ฟิลเตอร์เป็นทางออกที่เหมาะสมสำหรับกรณีการใช้งานจำนวนมากสำหรับการทำลาย
TKoL

แล้วประสิทธิภาพล่ะ ตัวกรอง Woudl จะไม่ส่งผลกระทบต่อประสิทธิภาพหากใช้บ่อยหรือไม่
tfrascaroli

ใช่ชุดต้นแบบของตัวกรองอาร์เรย์อาจมีน้ำหนักมาก ฉันชอบมัน แต่มันอาจส่งผลต่อการแสดงถ้ามันใช้งานมากเกินไป
ชาด

@tfrascaroli ใช้for...breakloop ถ้าคุณต้องการประสิทธิภาพ forห่วงมากที่สุดคือเครื่องมือ performant ย้ำกว่า.forEach(), .any(), .map(), .filter()ฯลฯ
แม็กซ์

6

นี่เป็นเพียงสิ่งที่ฉันคิดขึ้นเพื่อแก้ปัญหา ... ฉันค่อนข้างแน่ใจว่ามันแก้ปัญหาที่ผู้ถามเดิมมี:

Array.prototype.each = function(callback){
    if(!callback) return false;
    for(var i=0; i<this.length; i++){
        if(callback(this[i], i) == false) break;
    }
};

แล้วคุณจะเรียกมันโดยใช้:

var myarray = [1,2,3];
myarray.each(function(item, index){
    // do something with the item
    // if(item != somecondition) return false; 
});

การคืนค่า false ภายในฟังก์ชันการเรียกกลับจะทำให้เกิดการหยุด แจ้งให้เราทราบหากวิธีนี้ใช้ไม่ได้ผล


1
=== falseอาจดีกว่า== falseดังนั้นคุณไม่จำเป็นต้องส่งกลับค่าจริง (หรือค่าจริง) อย่างชัดเจนเพื่อดำเนินการวนรอบต่อไปเพื่อไม่ให้บางเส้นทางการควบคุมไม่ส่งคืนค่าและการวนซ้ำจะเกิดขึ้นโดยไม่คาดคิด
Jake

6

แนวคิดอื่นที่ฉันคิดขึ้น:

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(); }
});


ไวยากรณ์คล้ายกับ [NSArray enumerateObjectsUsingBlock] ขอบคุณ!
Chrstph SLN

@Drenai Array.prototype.forEach()ลายเซ็นจะคล้ายคลึงกับชาวพื้นเมือง forและbreakมีอยู่นานก่อนที่จะถามคำถามนี้ OP forEachได้รับการมองหาพฤติกรรมที่ใช้ในการทำงานมากขึ้น
c24w

@Drenai ลบในขณะนี้ความคิดเห็นของพวกเขา (เหลือ แต่ downvote) การที่บอกว่าลายเซ็นของการแก้ปัญหานี้เป็นเรื่องยากที่จะจำและไม่จำเป็นเมื่อคุณสามารถแก้ปัญหาด้วยและfor...in break
c24w

5

พบวิธีแก้ปัญหานี้ในเว็บไซต์อื่น คุณสามารถล้อม forEach ในสถานการณ์ลอง / จับได้

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

รายละเอียดเพิ่มเติมได้ที่นี่: http://dean.edwards.name/weblog/2006/07/enum/


2
อย่าใช้ข้อยกเว้นเป็นคำสั่งควบคุมการไหล ใช้สำหรับจัดการผลลัพธ์ที่ไม่คาดคิด
Max


4

หากคุณไม่จำเป็นต้องเข้าถึงอาเรย์ของคุณหลังจากการวนซ้ำคุณสามารถประกันตัวด้วยการตั้งค่าความยาวของอาเรย์เป็น 0 หากคุณยังคงต้องการมันหลังจากการทำซ้ำคุณสามารถโคลนมันโดยใช้สไลซ์ ..

[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
  if (index === 3) arr.length = 0;
});

หรือด้วยการโคลน:

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;
});

ซึ่งเป็นทางออกที่ดีกว่าแล้วโยนข้อผิดพลาดแบบสุ่มในรหัสของคุณ


ทำได้ดีมาก :) แต่ถ้ามีการกระทำบางอย่างหลังจากกำหนดให้array.lengthกับ0พวกเขาจะนำไปใช้ในการทำซ้ำปัจจุบันดังนั้นบางทีมันอาจจะดีกว่าที่จะใช้returnหลังจากการมอบหมายดังกล่าว
zhibirc

4

นี่เป็น for loop แต่รักษาการอ้างอิงวัตถุใน loop เหมือนกับ forEach () แต่คุณสามารถแยกย่อยได้

var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
    if(el === 1) break;
}

4

ตามที่กล่าวไว้ก่อนหน้านี้คุณไม่สามารถหยุด .forEach()ดังที่ได้กล่าวมาก่อนคุณไม่สามารถทำลาย

นี่เป็นวิธีที่ทันสมัยกว่าเล็กน้อยในการทำ foreach กับ ES6 Iterators อนุญาตให้คุณเข้าถึงโดยตรงindex/ valueเมื่อทำการวนซ้ำ

const array = ['one', 'two', 'three'];

for (const [index, val] of array.entries()) {
  console.log('item:', { index, val });
  if (index === 1) {
    console.log('break!');
    break;
  }
}

เอาท์พุท:

item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!

การเชื่อมโยง


3

อีกวิธีหนึ่ง

        var wageType = types.filter(function(element){
            if(e.params.data.text == element.name){ 
                return element;
            }
        });
        console.dir(wageType);

2

ฉันใช้nullhackเพื่อจุดประสงค์นั้นพยายามเข้าถึงคุณสมบัติของnullซึ่งเป็นข้อผิดพลาด:

try {
  [1,2,3,4,5]
  .forEach(
    function ( val, idx, arr ) {
      if ( val == 3 ) null.NULLBREAK;
    }
  );
} catch (e) {
  // e <=> TypeError: null has no properties
}
//

1
ทำไมไม่เป็นเช่นนั้นthrow BREAK?
Bergi

1

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

ตัวอย่างนี้ใช้ฟังก์ชั่นที่ไม่ระบุชื่อสำหรับการสร้างขอบเขตการทำงานรอบforEachที่คุณจะต้องเก็บทำข้อมูล

(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>

สองเซ็นต์ของฉัน




0

เห็นด้วยกับ @bobince, upvoted

นอกจากนี้ FYI:

Prototype.js มีบางอย่างสำหรับจุดประสงค์นี้:

<script type="text/javascript">
  $$('a').each(function(el, idx) {
    if ( /* break condition */ ) throw $break;
    // do something
  });
</script>

$break จะถูกจับและจัดการโดย Prototype.js ภายในทำลายวงจร "แต่ละ" แต่ไม่สร้างข้อผิดพลาดภายนอก

ดูPrototype.JS APIสำหรับรายละเอียด

jQuery ยังมีวิธีเพียงส่งคืนค่าเท็จในตัวจัดการเพื่อแบ่งลูปก่อน:

<script type="text/javascript">
  jQuery('a').each( function(idx) {
    if ( /* break condition */ ) return false;
    // do something

  });
</script>

ดูjQuery APIสำหรับรายละเอียด


0

สิ่งนี้ไม่ได้มีประสิทธิภาพมากที่สุดเนื่องจากคุณยังคงวนองค์ประกอบทั้งหมด แต่ฉันคิดว่ามันอาจจะคุ้มค่าเมื่อพิจารณาจากสิ่งที่ง่ายมาก:

let keepGoing = true;
things.forEach( (thing) => {
  if (noMore) keepGoing = false;
  if (keepGoing) {
     // do things with thing
  }
});

continueเป็นคำหลักรหัสของคุณเป็นข้อผิดพลาดทางไวยากรณ์
Bergi

3
ระบุว่าคุณกำลังใช้ ES6 อยู่แล้วคุณควรเปลี่ยนไปใช้for ofลูปและbreak;จากนั้นตามปกติ
Bergi

คงที่และเป็นจริง - แต่ส่วนใหญ่ใช้ es6 เพื่อความกะทัดรัด
martyman

0

คุณสามารถทำตามรหัสด้านล่างซึ่งใช้งานได้สำหรับฉัน:

 var     loopStop = false;
YOUR_ARRAY.forEach(function loop(){
    if(loopStop){ return; }
    if(condition){ loopStop = true; }
});

ทำไมต้อง -1 มันไม่ได้เป็นเรื่องน่าประหลาดไปกว่าการจับยกเว้นนั่นเป็น IMHO ที่แฮ็คที่ใหญ่กว่า
Byron Whitlock

0

ฉันชอบที่จะใช้ 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ทำงานได้เหมือนforEachและคุณสามารถเพิ่มฟังก์ชั่นย้อนกลับเพื่อออกจากภายใน ประสิทธิภาพที่ดีขึ้นเช่นกัน


0

หากคุณต้องการแบ่งตามมูลค่าขององค์ประกอบที่มีอยู่แล้วในอาร์เรย์ของคุณเช่นในกรณีของคุณ (เช่นหากเงื่อนไขการแบ่งไม่ขึ้นอยู่กับตัวแปรรันไทม์ที่อาจเปลี่ยนแปลงได้หลังจากกำหนดอาร์เรย์แล้วให้กำหนดค่าองค์ประกอบ) ของslice ()และindexOf ()ดังต่อไปนี้

หากคุณต้องการหยุดพักเมื่อถึง "Apple" คุณสามารถใช้

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
});

ตามที่ระบุใน W3Schools.comวิธี slice () จะคืนค่าองค์ประกอบที่เลือกในอาร์เรย์เป็นวัตถุอาร์เรย์ใหม่ อาร์เรย์เดิมจะไม่เปลี่ยนแปลง

ดูในJSFiddle

หวังว่าจะช่วยใครซักคน


0

คุณสามารถสร้างความแตกต่างของการforEachที่ช่วยให้การbreak, continue, returnและแม้กระทั่งasync/ await(ตัวอย่างเช่นเขียนใน typescript)

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];
    }
};

การใช้งาน:

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);
}

-1

ลองด้วย "ค้นหา":

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

-1

ใช่เป็นไปได้ที่จะดำเนินการต่อและออกจากลูป forEach แต่ละครั้ง

หากต้องการดำเนินการต่อคุณสามารถใช้การส่งคืนลูปจะดำเนินการต่อ แต่ฟังก์ชั่นปัจจุบันจะสิ้นสุด

หากต้องการออกจากลูปคุณสามารถตั้งค่าพารามิเตอร์ที่สามเป็น 0 ความยาวตั้งเป็นอาร์เรย์ว่าง การวนซ้ำจะไม่ดำเนินการต่อฟังก์ชั่นปัจจุบันทำเพื่อให้คุณสามารถใช้ "ย้อนกลับ" เพื่อเสร็จสิ้นเช่นออกในปกติสำหรับวง ...

นี้:

[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);
});

จะพิมพ์สิ่งนี้:

1
next... 0
2
next... 1
3
4
next... 3
5

-2

ก่อนหน้ารหัสของฉันอยู่ด้านล่าง

 this.state.itemsDataSource.forEach((item: any) => {
                if (!item.isByPass && (item.invoiceDate == null || item.invoiceNumber == 0)) {

                    return false;
                }
            });

ฉันเปลี่ยนเป็นด้านล่างมันได้รับการแก้ไข

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