การวนซ้ำคุณสมบัติในวัตถุ วิธีทั้งหมดในการวนซ้ำผ่านอาร์เรย์ใน JavaScript หมายเหตุเกี่ยวกับรันไทม์ออบเจ็กต์

ที่ สำหรับแต่ละ()วิธีการรันฟังก์ชันที่ให้มาหนึ่งครั้งสำหรับแต่ละองค์ประกอบอาร์เรย์

แหล่งที่มาของตัวอย่างเชิงโต้ตอบนี้จัดเก็บไว้ในที่เก็บ GitHub หากคุณต้องการมีส่วนร่วมในโครงการตัวอย่างเชิงโต้ตอบ โปรดโคลน https://github.com/mdn/interactive-examples และส่งคำขอดึงถึงเรา

ไวยากรณ์

arr .forEach(โทรกลับ(currentValue [, ดัชนี [, อาร์เรย์]]) [, thisArg ]);

พารามิเตอร์

ฟังก์ชั่นเรียกกลับเพื่อดำเนินการกับแต่ละองค์ประกอบโดยรับสามอาร์กิวเมนต์: currentValue องค์ประกอบปัจจุบันที่กำลังประมวลผลในอาร์เรย์

ดัชนี ตัวเลือก ดัชนีขององค์ประกอบปัจจุบันที่กำลังประมวลผลในอาร์เรย์

อาร์เรย์ ตัวเลือก อาร์เรย์ forEach() ถูกเรียกใช้

thisArg Optional Value เพื่อใช้เช่นนี้เมื่อดำเนินการโทรกลับ

ส่งคืนค่า

  1. คำอธิบาย
  2. forEach() เรียกใช้ฟังก์ชันเรียกกลับที่ให้ไว้หนึ่งครั้งสำหรับแต่ละองค์ประกอบในอาร์เรย์จากน้อยไปหามาก ไม่มีการเรียกใช้สำหรับคุณสมบัติดัชนีที่ถูกลบหรือไม่ได้เตรียมใช้งาน (เช่น บนอาร์เรย์แบบกระจาย )
  3. โทรกลับถูกเรียกใช้โดยมีสามข้อโต้แย้ง:

ค่าขององค์ประกอบ

ดัชนีขององค์ประกอบ

วัตถุ Array ที่กำลังเคลื่อนที่

หากระบุพารามิเตอร์ thisArg ให้กับ forEach() ก็จะถูกใช้เป็นค่านี้ของการโทรกลับ ในที่สุดค่านี้จะถูกสังเกตได้โดยการโทรกลับจะถูกกำหนดตามกฎปกติสำหรับการพิจารณาค่านี้ที่ฟังก์ชันเห็น

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

การเลิกจ้างก่อนกำหนดอาจทำได้ด้วย:

วิธีการอาร์เรย์: every() , some() , find() และ findIndex() ทดสอบองค์ประกอบอาร์เรย์ด้วยเพรดิเคตส่งคืนค่าความจริงเพื่อพิจารณาว่าจำเป็นต้องมีการวนซ้ำเพิ่มเติมหรือไม่

ตัวอย่าง

ไม่มีการดำเนินการสำหรับค่าที่ไม่ได้เตรียมใช้งาน (อาร์เรย์แบบกระจาย)

const arraySparse = ; ให้ numCallbackRuns = 0; arraySparse.forEach(ฟังก์ชั่น(องค์ประกอบ)( console.log(องค์ประกอบ); numCallbackRuns++; )); console.log("numCallbackRuns: ", numCallbackRuns); // 1 // 3 // 7 // numCallbackRuns: 3 // comment: ดังที่คุณเห็นค่าที่หายไประหว่าง 3 ถึง 7 ไม่ได้เรียกใช้ฟังก์ชันการโทรกลับ

การแปลง for loop เป็น forEach

รายการ const = ["item1", "item2", "item3"]; สำเนา const = ; // ก่อน สำหรับ (ให้ i=0; i การพิมพ์เนื้อหาของอาร์เรย์

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

รหัสต่อไปนี้บันทึกบรรทัดสำหรับแต่ละองค์ประกอบในอาร์เรย์:

ฟังก์ชั่น logArrayElements(องค์ประกอบ, ดัชนี, อาร์เรย์) ( console.log("a[" + index + "] = " + element); ) // สังเกตว่าดัชนี 2 ถูกข้ามไปเนื่องจากไม่มีรายการที่ // ตำแหน่งนั้นใน อาร์เรย์ .forEach(logArrayElements); // บันทึก: // a = 2 // a = 5 // a = 9

การใช้ thisArg

ตัวอย่างต่อไปนี้ (ที่ประดิษฐ์ขึ้น) จะอัพเดตคุณสมบัติของอ็อบเจ็กต์จากแต่ละรายการในอาร์เรย์:

ตัวนับฟังก์ชัน() ( this.sum = 0; this.count = 0; ) Counter.prototype.add = function(array) ( array.forEach(function(entry) ( this.sum += entry; ++this.count ; ) นี่); // ^---- หมายเหตุ); const obj = ตัวนับใหม่ (); obj.เพิ่ม(); obj.นับ; // 3 obj.sum; // 16

เนื่องจากพารามิเตอร์ thisArg (this) มีให้กับ forEach() มันจะถูกส่งผ่านไปยังการโทรกลับทุกครั้งที่มีการเรียกใช้ เพื่อใช้เป็นค่านี้

ฟังก์ชั่นการคัดลอกวัตถุ

รหัสต่อไปนี้สร้างสำเนาของวัตถุที่กำหนด มีหลายวิธีในการสร้างสำเนาของออบเจ็กต์ ต่อไปนี้เป็นเพียงวิธีหนึ่งและนำเสนอเพื่ออธิบายวิธีการทำงานของ Array.prototype.forEach() โดยใช้ฟังก์ชันคุณสมบัติเมตาของ ECMAScript 5 Object.*

ฟังก์ชั่นคัดลอก (obj) ( const copy = Object.create(Object.getPrototypeOf(obj)); const propNames = Object.getOwnPropertyNames(obj); propNames.forEach(function(name) ( const desc = Object.getOwnPropertyDescriptor(obj, ชื่อ ); Object.defineProperty (สำเนา, ชื่อ, คำอธิบาย )); const obj2 = คัดลอก (obj1); // obj2 ดูเหมือน obj1 เลยตอนนี้

หากมีการแก้ไขอาร์เรย์ระหว่างการวนซ้ำ องค์ประกอบอื่นๆ อาจถูกข้ามไป

ตัวอย่างต่อไปนี้บันทึก "หนึ่ง", "สอง", "สี่" เมื่อรายการมีค่า "two" is reached, the first entry of the whole array is shifted off, which results in all remaining entries moving up one position. Because element "four" is now at an earlier position in the array, "three" will be skipped. forEach() does not make a copy of the array before iterating.!}

คำวาร์ = ["หนึ่ง", "สอง", "สาม", "สี่"]; word.forEach(function(word) ( console.log(word); if (word === "สอง") ( word.shift(); ) )); // หนึ่ง // สอง // สี่

แผ่อาร์เรย์

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

/** * แผ่อาร์เรย์ที่ส่งผ่านในอาร์เรย์หนึ่งมิติ * * @params (array) arr * @returns (array) */ function flatten(arr) ( const result = arr.forEach((i) => ( if (Array. isArray(i)) ( result.push(...flatten(i)) ) else ( result.push(i) )) return result ) // การใช้งาน const problems = , 8, 9]] flatten(problem) / /

ข้อมูลจำเพาะ

ข้อมูลจำเพาะ สถานะ ความคิดเห็น
ECMAScript ฉบับร่างล่าสุด (ECMA-262)
ร่าง
ECMAScript 2015 (ฉบับที่ 6, ECMA-262)
คำจำกัดความของ "Array.prototype.forEach" ในข้อกำหนดนั้น
มาตรฐาน
ECMAScript 5.1 (ECMA-262)
คำจำกัดความของ "Array.prototype.forEach" ในข้อกำหนดนั้น
มาตรฐาน คำจำกัดความเริ่มต้น ใช้งานใน JavaScript 1.6

ความเข้ากันได้ของเบราว์เซอร์

ตารางความเข้ากันได้ในหน้านี้สร้างขึ้นจากข้อมูลที่มีโครงสร้าง หากคุณต้องการมีส่วนร่วมในข้อมูล โปรดตรวจสอบ https://github.com/mdn/browser-compat-data และส่งคำขอดึงถึงเรา

อัปเดตข้อมูลความเข้ากันได้บน GitHub

เดสก์ท็อปมือถือเซิร์ฟเวอร์
โครเมียมขอบไฟร์ฟอกซ์อินเทอร์เน็ตเอ็กซ์พลอเรอร์โอเปร่าซาฟารีมุมมองเว็บ Androidโครมสำหรับแอนดรอยด์ไฟร์ฟอกซ์สำหรับ Androidโอเปร่าสำหรับ Androidซาฟารีบน iOSซัมซุงอินเตอร์เน็ตโหนด js
สำหรับแต่ละรองรับ Chrome เต็มรูปแบบ ใช่รองรับ Edge เต็มรูปแบบ 12Firefox รองรับเวอร์ชันเต็ม 1.5การสนับสนุน IE เต็มรูปแบบ 9รองรับ Opera เต็มรูปแบบ ใช่รองรับ Safari เต็มรูปแบบ ใช่รองรับ WebView Android เต็มรูปแบบ ใช่รองรับ Chrome Android เต็มรูปแบบใช่Firefox Android รองรับเต็มรูปแบบ 4รองรับ Opera Android เต็มรูปแบบ ใช่Safari iOS รองรับเต็มรูปแบบ ใช่Samsung Internet Android รองรับเต็มรูปแบบ ใช่nodejs รองรับเต็มที่ ใช่

12 มี.ค. 2559

ใน JavaScript สมัยใหม่ มีสิ่งที่เรียกว่า "วิธีการวนซ้ำ" ซึ่งใช้ในการวนซ้ำผ่านอาร์เรย์ ในบทช่วยสอนนี้ เราจะกล่าวถึงวิธีการต่อไปนี้:

สำหรับแต่ละ

.forEach() วิธีการใช้สำหรับ ค้นหาอาร์เรย์ มันเรียกสิ่งที่เรียกว่าฟังก์ชันการโทรกลับด้วยความช่วยเหลือของรายการพารามิเตอร์สามรายการ i, arr จะถูกส่งผ่านโดยที่:

  • รายการ — องค์ประกอบอาร์เรย์;
  • i คือหมายเลขซีเรียลของอาเรย์
  • arr คืออาร์เรย์ที่ควรวนซ้ำ

เพื่อให้เข้าใจวิธีใช้วิธีนี้ได้ง่ายขึ้น ลองพิจารณาตัวอย่าง:

ผู้ใช้ Var=["admin","pass",31]; user.forEach(function(item,i,user)( alert("มูลค่าของหมายเลขรายการ " + i + " : " + item); ));

วิธีการนี้สามารถใช้แทนการวนซ้ำปกติได้

กรอง

เมธอด .filter() ใช้สำหรับการกรอง และยังใช้ฟังก์ชันเรียกกลับด้วย แต่จะสร้างอาร์เรย์ใหม่หากองค์ประกอบในอาร์เรย์ตรงกับค่าจริง:

วาร์ arr=; var newArr=arr.filter(function(number)( return number< 0; }); alert(newArr); // выведет -34,-4

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

ทุก / บางส่วน

ทั้งสองวิธีนี้มีความคล้ายคลึงกัน และทั้งสองวิธีใช้เพื่อตรวจสอบอาร์เรย์ เฉพาะวิธีการเท่านั้น .ทั้งหมด()คืนค่าเป็นจริงหากค่าทั้งหมดในอาร์เรย์ตรงกับเงื่อนไขที่ระบุและวิธีการ .บาง()คืนค่าเป็นจริงหากมีอย่างน้อยหนึ่งค่าที่ตรงกับเงื่อนไข:

วาร์ arr=; alert(arr.every(function(number)( return number< 0; })); // выведет false

ฉันหวังว่ามันชัดเจนว่าหากในตัวอย่างข้างต้นเราใช้ วิธีการบางอย่างจากนั้นเราจะแสดงค่าจริงแทนที่จะเป็นเท็จ

แผนที่

เมธอด .map() จะแปลงอาร์เรย์และรับอาร์เรย์ใหม่จากอาร์เรย์นั้น ทุกอย่างทำได้โดยการเรียกฟังก์ชันโทรกลับ:

วาร์ arr=; var newArr=arr.map(function(number)( return number*2; )); การแจ้งเตือน (newArr);

ในตัวอย่างนี้ เราได้รับอาร์เรย์ใหม่ที่มีค่าองค์ประกอบสองเท่า

ลด/ลดขวา

วิธีสุดท้ายที่เราจะพิจารณาคือ ลด และ ลดขวา ใช้ในการประมวลผลแต่ละองค์ประกอบของอาร์เรย์ในขณะที่บันทึกผลลัพธ์ระดับกลาง เมธอดจะวนซ้ำแต่ละองค์ประกอบจากซ้ายไปขวา ส่วน ลดRight จะทำตรงกันข้าม แตกต่างจากวิธีการอื่น ๆ นอกเหนือจากฟังก์ชันการโทรกลับแล้ว อาร์กิวเมนต์ defaultValue ยังถูกระบุที่นี่ด้วย - "ค่าเริ่มต้น" นอกจากนี้ฟังก์ชันการโทรกลับยังระบุ "ผลลัพธ์ระดับกลาง" - ค่าก่อนหน้าและ รายการปัจจุบัน— องค์ประกอบปัจจุบันของอาร์เรย์

ลองดูตัวอย่าง:

ฟังก์ชัน getSums(arr) ( var result = ; if (!arr.length) ส่งคืนผลลัพธ์; var TotalSum = arr.reduceRight(function(sum, item) ( result.push(sum); return sum + item; )); result .push(totalSum); ส่งคืนการแจ้งเตือน (getSums()); // 1,3,6,10,15

เกิดอะไรขึ้นในตัวอย่างนี้? เราได้สร้างฟังก์ชันที่ช่วยให้เราได้รับอาร์เรย์ใหม่พร้อมองค์ประกอบที่สร้างขึ้นจากผลรวมของอาร์เรย์ก่อนหน้า นอกจากนี้รายงานองค์ประกอบยังมาจากส่วนท้ายอีกด้วย และนี่คือตัวอย่างที่ง่ายกว่าที่ฉันสร้างฟังก์ชันที่คำนวณผลรวมขององค์ประกอบในอาร์เรย์:

ฟังก์ชัน getSum(arr) ( var result = arr.reduce(function(sum, current) ( return sum + current )); return result; ); การแจ้งเตือน(getSum());

แท็ก: 

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

ห่วงสำหรับ..ใน

ไวยากรณ์:

สำหรับ (ป้อน obj) ( /* ... การดำเนินการกับ obj ... */ )

for..in วนซ้ำตามลำดับผ่านคุณสมบัติของวัตถุ obj โดยเขียนชื่อของแต่ละคุณสมบัติลงในคีย์

การประกาศตัวแปรใน for loop (คีย์ var ใน obj)

ในลูปนี้ คุณสามารถประกาศตัวแปรหลักได้:

สำหรับ (คีย์ var ใน menu1) ( // ... )

ลองดูตัวอย่างการวนซ้ำคุณสมบัติของวัตถุโดยใช้ for...in loop:

เมนู Var = (กว้าง: 400, สูง: 300, ชื่อ: "เมนูของฉัน" ); for (คีย์ var ในเมนู) ( // รหัสนี้จะใช้ได้กับแต่ละคุณสมบัติของอ็อบเจ็กต์ // ..และจะแสดงชื่อคุณสมบัติและค่าของมันตามลำดับ alert("Key: " + key + " value: " + menu) ; )

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

ห่วงสำหรับ...ของ

นอกจากนี้ยังมีการวนซ้ำใหม่สำหรับการสำรวจวัตถุและอาร์เรย์ ไวยากรณ์ของมันคล้ายกับลูป for...in มาก แต่ข้อแตกต่างก็คือ มันไม่ได้ส่งออกคีย์หรือดัชนีของอาร์เรย์ แต่เป็นค่าของมัน นี่คือตัวอย่าง:

เมนู Var = (กว้าง: 400, สูง: 300, ชื่อ: "เมนูของฉัน" ); สำหรับ (คีย์ var ของเมนู) ( // รหัสนี้จะใช้ได้กับแต่ละคุณสมบัติของวัตถุ // ..และแสดงค่าคุณสมบัติตามการแจ้งเตือน ("value: " + key +","); //400, 300, "เมนูของฉัน")

จำนวนคุณสมบัติในวัตถุ

แต่ถ้าคุณต้องการทราบจำนวนคุณสมบัติในวัตถุล่ะ? สิ่งนี้สามารถทำได้อย่างไร?

ขออภัย ไม่มีวิธีแก้ไขปัญหาแบบสำเร็จรูปสำหรับปัญหานี้

เมนู Var = (กว้าง: 400, สูง: 300, ชื่อ: "เมนูของฉัน" ); จำนวนนับ = 0; สำหรับ (คีย์ var ในเมนู) ( count++; ) alert("คุณสมบัติทั้งหมด: " + count);

ผลลัพธ์

  • ในการวนซ้ำคุณสมบัติของวัตถุ จะใช้คีย์ลูป: for (คีย์ใน obj)

งาน

ตรวจสอบว่าวัตถุว่างเปล่าหรือไม่

สร้างฟังก์ชัน isEmptyObject(obj) ที่คืนค่าเป็นจริงหากวัตถุไม่มีคุณสมบัติ และคืนค่าเป็นเท็จหากมีคุณสมบัติอย่างน้อยหนึ่งรายการ

มันควรจะทำงานเช่นนี้:

ฟังก์ชั่น isEmptyObject(obj) ( /* รหัสของคุณ */ ) var obj = (); การแจ้งเตือน (isEmptyObject (obj)); // จริง obj["8:30"] = "ลุกขึ้น"; การแจ้งเตือน (isEmptyObject (obj)); // เท็จ

คำนวณค่าเฉลี่ยเลขคณิตของคุณสมบัติของวัตถุทั้งหมด

มีวัตถุเงินเดือนพร้อมเงินเดือน เขียนโค้ดที่จะแสดงค่าเฉลี่ยเลขคณิตของเงินเดือนทั้งหมด
หากวัตถุว่างเปล่า ผลลัพธ์ควรเป็น 0
ตัวอย่างเช่น.

มันทำงานเช่นนี้:

// ต้องการ ECMASCRIPT 2015+ var s, myStringArray = ["Hello", "World"]; สำหรับ (s ของ myStringArray) ( // ... ทำบางสิ่งบางอย่างกับ s ... )

หรือดีกว่านั้น เนื่องจาก ECMAScript 2015 ยังมีตัวแปรในขอบเขตแบบบล็อกด้วย lalet และ const:

// ต้องการ ECMASCRIPT 2015+ const myStringArray = ["Hello", "World"]; for (const s of myStringArray) ( // ... do something with s ... ) // s ไม่ได้ถูกกำหนดไว้ที่นี่อีกต่อไป

หมายเหตุเกี่ยวกับอาร์เรย์แบบกระจาย: อาร์เรย์ใน JavaScript อาจไม่จัดเก็บองค์ประกอบได้มากตามที่ระบุไว้ในความยาว; ตัวเลขที่รายงานนี้มีค่ามากกว่าดัชนีสูงสุดที่ใช้จัดเก็บค่าไว้เพียงหนึ่งค่า หากอาร์เรย์มีองค์ประกอบน้อยกว่าความยาวที่ระบุ ถือว่าเบาบาง ตัวอย่างเช่น การมีอาร์เรย์ที่มีองค์ประกอบเฉพาะที่ดัชนี 3, 12 และ 247 เท่านั้นถือเป็นเรื่องถูกกฎหมาย ความยาวของอาร์เรย์ดังกล่าวแสดงเป็น 248 แม้ว่าในความเป็นจริงจะเก็บค่าได้เพียง 3 ค่าเท่านั้น หากคุณพยายามเข้าถึงองค์ประกอบที่ดัชนีอื่น อาร์เรย์จะมีค่าที่ไม่ได้กำหนด ดังนั้นเมื่อคุณต้องการ "วนซ้ำ" อาร์เรย์ คุณมีคำถามที่ต้องตอบ: คุณต้องการวนซ้ำตลอดช่วงทั้งหมดที่ระบุโดยความยาวและประมวลผลไม่ได้กำหนดไว้สำหรับองค์ประกอบที่ขาดหายไป หรือคุณต้องการประมวลผลเฉพาะ มีองค์ประกอบอยู่จริงหรือ? มีแอปพลิเคชันมากมายสำหรับทั้งสองวิธี มันขึ้นอยู่กับว่าคุณใช้อาเรย์เพื่ออะไร

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

แน่นอนว่านักพัฒนาบางรายไม่มีทางเลือกอื่นนอกจากต้องใช้แนวทางอื่น เนื่องจากด้วยเหตุผลบางประการ พวกเขาจึงกำหนดเป้าหมายเวอร์ชันของ JavaScript ที่ยังไม่รองรับ ... of .

ตราบใดที่การใช้งาน JavaScript ของคุณเข้ากันได้กับเวอร์ชันก่อนหน้าของข้อกำหนด ECMAScript (ซึ่ง ตัวอย่างเช่น ยกเว้นเวอร์ชันของ Internet Explorer ก่อน 9) คุณสามารถใช้เมธอด Array#forEach ตัววนซ้ำ แทนการวนซ้ำได้ ในกรณีนี้ คุณจะต้องส่งฟังก์ชันที่จะถูกเรียกสำหรับแต่ละองค์ประกอบในอาร์เรย์:

Var myStringArray = [ "สวัสดี", "โลก" ]; myStringArray.forEach(function(s) ( // ... do something with s ... ));

ต่างจาก for ... of , .forEach เรียกใช้ฟังก์ชันบนองค์ประกอบที่มีค่าจริงเท่านั้น ถ้าเราส่งผ่านอาร์เรย์สมมุติที่มีสามองค์ประกอบและมีความยาว 248 มันจะเรียกใช้ฟังก์ชันเพียงสามครั้งเท่านั้น ไม่ใช่ 248 ครั้ง นอกจากนี้ยังแยกความแตกต่างระหว่างองค์ประกอบที่ขาดหายไปและองค์ประกอบที่ตั้งค่าเป็น undef จริง ๆ ; สำหรับอย่างหลัง มันจะยังคงเรียกใช้ฟังก์ชัน โดยส่งค่าที่ไม่ได้กำหนดเป็นอาร์กิวเมนต์ หากนี่คือวิธีที่คุณต้องการจัดการกับอาร์เรย์แบบกระจาย .forEach อาจเป็นวิธีที่จะไป แม้ว่านักแปลของคุณจะรองรับ ... ของ .

ตัวเลือกสุดท้ายซึ่งใช้ได้กับ JavaScript ทุกเวอร์ชันคือการวนซ้ำที่ชัดเจน คุณเพียงแค่นับ 0 ถึง 1 ที่น้อยกว่าความยาวและใช้ตัวนับเป็นดัชนี ลูปหลักมีลักษณะดังนี้:

ข้อดีประการหนึ่งของแนวทางนี้คือคุณสามารถเลือกวิธีจัดการกับอาร์เรย์แบบกระจายได้ โค้ดด้านบนจะเรียกใช้เนื้อหาลูปตลอดความยาวเต็ม โดยมีการตั้งค่า s เป็น undef สำหรับองค์ประกอบที่ขาดหายไป เช่น สำหรับ .. of หากคุณต้องการประมวลผลเฉพาะองค์ประกอบที่มีอยู่จริงของอาร์เรย์แบบกระจาย เช่น .forEach คุณสามารถเพิ่มการตรวจสอบง่ายๆ ลงในดัชนีแทน:

Var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length; สำหรับ (i=0; i

การกำหนดค่าความยาวให้กับตัวแปรโลคัล (ตรงข้ามกับการรวมนิพจน์ myStringArray.length แบบเต็มในเงื่อนไขลูป) อาจมีผลกระทบต่อประสิทธิภาพการทำงานที่สำคัญ เนื่องจากจะข้ามการค้นหาคุณสมบัติไปตลอดในแต่ละครั้ง เมื่อใช้ Rhino บนเครื่องของฉัน ความเร็วจะอยู่ที่ 43%

คุณจะเห็นว่าการแคชความยาวเสร็จสิ้นแล้วในส่วนคำสั่งการเริ่มต้นลูป เช่นนี้

ฉัน, len, myStringArray = [ "สวัสดี", "โลก" ]; สำหรับ (len = myStringArray.length, i=0; i

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

  • I. วนซ้ำอาร์เรย์จริง
    1. สำหรับแต่ละวิธีและวิธีการที่เกี่ยวข้อง
    2. สำหรับวง
    3. การใช้ for...in loop อย่างเหมาะสม
    4. for...of loop (การใช้ตัววนซ้ำโดยนัย)
    5. การใช้ตัววนซ้ำอย่างชัดเจน
  • ครั้งที่สอง วนซ้ำวัตถุที่มีลักษณะคล้ายอาเรย์
    1. การใช้เมธอดเพื่อวนซ้ำอาร์เรย์จริง
    2. แปลงเป็นอาร์เรย์จริง
    3. หมายเหตุเกี่ยวกับออบเจ็กต์รันไทม์

I. การวนซ้ำอาร์เรย์จริง

ในขณะนี้ มีสามวิธีในการวนซ้ำองค์ประกอบของอาร์เรย์จริง:

  1. วิธีการ Array.prototype.forEach ;
  2. คลาสสิกสำหรับวง
  3. สร้าง "อย่างถูกต้อง" สำหรับ...ในลูป

นอกจากนี้ เร็วๆ นี้ ด้วยการถือกำเนิดของมาตรฐาน ECMAScript 6 (ES 6) ใหม่ คาดว่าจะมีอีกสองวิธี:

  1. for...of loop (การใช้ตัววนซ้ำโดยนัย);
  2. การใช้ตัววนซ้ำอย่างชัดเจน

1. วิธี forEach และวิธีการที่เกี่ยวข้อง

หากโครงการของคุณได้รับการออกแบบเพื่อรองรับคุณสมบัติของมาตรฐาน ECMAScript 5 (ES5) คุณสามารถใช้นวัตกรรมอย่างใดอย่างหนึ่ง - วิธี forEach

ตัวอย่างการใช้งาน:

วาร์ = ["a", "b", "c"]; a.forEach(ฟังก์ชั่น(รายการ) ( console.log(รายการ); ));

โดยทั่วไป การใช้ forEach จำเป็นต้องเชื่อมต่อไลบรารีการจำลอง es5-shim สำหรับเบราว์เซอร์ที่ไม่รองรับวิธีนี้โดยกำเนิด ซึ่งรวมถึง IE 8 และเวอร์ชันก่อนหน้า ซึ่งยังคงมีการใช้งานอยู่ในบางแห่ง

ข้อดีของ forEach คือไม่จำเป็นต้องประกาศตัวแปรในเครื่องเพื่อจัดเก็บดัชนีและค่าขององค์ประกอบอาร์เรย์ปัจจุบัน เนื่องจากตัวแปรเหล่านั้นจะถูกส่งผ่านไปยังฟังก์ชันเรียกกลับโดยอัตโนมัติเป็นอาร์กิวเมนต์

หากคุณกังวลเกี่ยวกับค่าใช้จ่ายที่อาจเกิดขึ้นในการโทรกลับในแต่ละองค์ประกอบ ไม่ต้องกังวลและอ่านข้อความนี้

forEach ได้รับการออกแบบมาเพื่อวนซ้ำองค์ประกอบทั้งหมดของอาร์เรย์ แต่นอกจากนั้น ES5 ยังมีวิธีที่มีประโยชน์อีกมากมายสำหรับการวนซ้ำองค์ประกอบทั้งหมดหรือบางส่วน พร้อมทั้งดำเนินการบางอย่างกับองค์ประกอบเหล่านั้น:

  • every - ส่งคืน true หากแต่ละองค์ประกอบของอาร์เรย์ callback ส่งคืนค่าที่สามารถแปลงเป็น true ได้
  • some - คืนค่าจริงหากองค์ประกอบอย่างน้อยหนึ่งรายการในอาร์เรย์ที่เรียกกลับจะส่งกลับค่าที่สามารถแปลงเป็นจริงได้
  • ตัวกรอง - สร้างอาร์เรย์ใหม่ที่มีองค์ประกอบของอาร์เรย์เดิมซึ่งการเรียกกลับส่งคืน true
  • map - สร้างอาร์เรย์ใหม่ซึ่งประกอบด้วยค่าที่ส่งคืนโดยการเรียกกลับ
  • ลด - ลดอาร์เรย์ให้เป็นค่าเดียว โดยใช้การเรียกกลับไปยังแต่ละองค์ประกอบอาร์เรย์ตามลำดับ โดยเริ่มจากองค์ประกอบแรก (มีประโยชน์สำหรับการคำนวณผลรวมขององค์ประกอบอาร์เรย์และฟังก์ชันสรุปอื่นๆ)
  • ลดขวา - ทำงานคล้ายกับการลด แต่วนซ้ำผ่านองค์ประกอบในลำดับย้อนกลับ

2. สำหรับวง

เก่าดีสำหรับกฎเกณฑ์:

วาร์ = ["a", "b", "c"]; ดัชนี var; สำหรับ (ดัชนี = 0; ดัชนี< a.length; ++index) { console.log(a); }

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

วาร์ = ["a", "b", "c"]; ดัชนี var, len; สำหรับ (ดัชนี = 0, len = a.length; ดัชนี< len; ++index) { console.log(a); }

ตามทฤษฎีแล้ว โค้ดนี้ควรจะทำงานเร็วกว่าโค้ดก่อนหน้าเล็กน้อย

หากลำดับขององค์ประกอบไม่สำคัญคุณสามารถไปไกลกว่านี้ในแง่ของการปรับให้เหมาะสมและกำจัดตัวแปรสำหรับจัดเก็บความยาวของอาเรย์โดยเปลี่ยนลำดับการค้นหาเป็นแบบย้อนกลับ:

วาร์ = ["a", "b", "c"]; ดัชนี var; สำหรับ (ดัชนี = a.length - 1; ดัชนี >= 0; --index) ( console.log(a); )

อย่างไรก็ตาม ในเอ็นจิ้น JavaScript สมัยใหม่ เกมการปรับให้เหมาะสมนั้นมักจะไม่มีความหมายอะไรเลย

3. การใช้ for...in loop อย่างถูกต้อง

หากคุณได้รับคำแนะนำให้ใช้ for...in ลูป โปรดจำไว้ว่าการวนซ้ำอาร์เรย์ไม่ใช่สิ่งที่ตั้งใจไว้ ตรงกันข้ามกับความเข้าใจผิดทั่วไป for...in loop จะไม่วนซ้ำดัชนีอาร์เรย์ แต่จะวนซ้ำผ่านคุณสมบัติที่นับได้ของอ็อบเจ็กต์

อย่างไรก็ตาม ในบางกรณี เช่น การวนซ้ำอาร์เรย์แบบกระจาย for...in อาจมีประโยชน์ได้ ตราบใดที่คุณใช้ความระมัดระวัง ดังที่แสดงในตัวอย่างด้านล่าง:

// a - อาร์เรย์กระจัดกระจาย var a = ; เป็น = "เป็น"; ก = "ข"; มี = "ค"; สำหรับ (คีย์ var ใน a) ( if (a.hasOwnProperty(key) && /^0$|^d*$/.test(key) && key<= 4294967294) { console.log(a); } }

ในตัวอย่างนี้ มีการดำเนินการตรวจสอบสองครั้งในการวนซ้ำแต่ละครั้ง:

  1. ว่าอาร์เรย์มีคุณสมบัติของตัวเองที่เรียกว่าคีย์ (ไม่ได้สืบทอดมาจากต้นแบบ)
  2. คีย์นั้นเป็นสตริงที่มีการแทนทศนิยมของจำนวนเต็มที่มีค่าน้อยกว่า 4294967294 เลขท้ายมาจากไหน? จากคำจำกัดความของดัชนีอาร์เรย์ใน ES5 ซึ่งแสดงให้เห็นว่าดัชนีสูงสุดที่องค์ประกอบในอาร์เรย์สามารถมีได้คือ: (2^32 - 2) = 4294967294

แน่นอนว่าการตรวจสอบดังกล่าวจะใช้เวลาโดยไม่จำเป็นเมื่อดำเนินการวนซ้ำ แต่ในกรณีของอาร์เรย์แบบกระจาย วิธีการนี้จะมีประสิทธิภาพมากกว่าการวนซ้ำ เนื่องจากในกรณีนี้เฉพาะองค์ประกอบที่กำหนดไว้อย่างชัดเจนในอาร์เรย์เท่านั้นที่จะถูกวนซ้ำ ดังนั้น ในตัวอย่างข้างต้น จะมีการดำเนินการวนซ้ำเพียง 3 ครั้งเท่านั้น (สำหรับดัชนี 0, 10 และ 10,000) เทียบกับ 10,001 ในลูป for

เพื่อไม่ให้เขียนโค้ดตรวจสอบที่ยุ่งยากทุกครั้งที่คุณต้องการวนซ้ำผ่านอาร์เรย์ คุณสามารถเขียนเป็นฟังก์ชันแยกต่างหากได้:

ฟังก์ชั่น arrayHasOwnIndex(array, key) ( return array.hasOwnProperty(key) && /^0$|^d*$/.test(key) && key<= 4294967294; }

จากนั้นเนื้อความของลูปจากตัวอย่างจะลดลงอย่างมาก:

สำหรับ (ป้อน a) ( if (arrayHasOwnIndex(a, key)) ( console.log(a); ) )

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

สำหรับ (ป้อน a) ( if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) ( console.log(a); ) )

4. For...of loop (การใช้ตัววนซ้ำโดยนัย)

ES6 ซึ่งยังอยู่ในสถานะแบบร่าง ควรแนะนำตัววนซ้ำกับ JavaScript

ตัววนซ้ำ เป็นโปรโตคอลที่ดำเนินการโดยวัตถุที่กำหนดวิธีมาตรฐานในการรับลำดับของค่า (จำกัด หรือไม่มีที่สิ้นสุด)
วัตถุมีตัววนซ้ำหากกำหนดวิธีการ next() ซึ่งเป็นฟังก์ชันที่ไม่มีอาร์กิวเมนต์ที่ส่งคืนวัตถุที่มีคุณสมบัติสองประการ:

  1. เสร็จสิ้น (บูลีน) - เป็นจริงหากตัววนซ้ำถึงจุดสิ้นสุดของลำดับที่สามารถวนซ้ำได้ มิฉะนั้นค่าจะเป็นเท็จ
  2. ค่า - กำหนดค่าที่ส่งคืนโดยตัววนซ้ำ อาจไม่ได้กำหนด (หายไป) หากคุณสมบัติที่ทำเสร็จแล้วเป็นจริง

วัตถุในตัวมากมายรวมถึง อาร์เรย์จริงจะมีตัววนซ้ำตามค่าเริ่มต้น วิธีที่ง่ายที่สุดในการใช้ตัววนซ้ำบนอาร์เรย์จริงคือการใช้ new for...of build

ตัวอย่างการใช้ for...of:

วาร์วาล; วาร์ = ["a", "b", "c"]; สำหรับ (val ของ a) ( console.log(val); )

ในตัวอย่างข้างต้น for...of loop จะเรียกตัววนซ้ำของอ็อบเจ็กต์ Array โดยปริยายเพื่อรับค่าแต่ละค่าของอาร์เรย์

5. การใช้ตัววนซ้ำอย่างชัดเจน

ตัววนซ้ำยังสามารถนำมาใช้อย่างชัดเจนได้ แต่ในกรณีนี้โค้ดจะซับซ้อนกว่ามากเมื่อเทียบกับ for...of loop มีลักษณะดังนี้:

วาร์ = ["a", "b", "c"]; รายการ var; ในขณะที่ (!(entry = a.next()).done) ( console.log(entry.value); )

ครั้งที่สอง วนซ้ำวัตถุที่มีลักษณะคล้ายอาเรย์

นอกจากอาร์เรย์จริงแล้ว ใน JavaScript ยังมีอีกด้วย วัตถุที่มีลักษณะคล้ายอาร์เรย์ - สิ่งที่เหมือนกันกับอาร์เรย์จริงคือมีคุณสมบัติความยาวและคุณสมบัติที่ตั้งชื่อเป็นตัวเลขที่สอดคล้องกับองค์ประกอบของอาร์เรย์ ตัวอย่างได้แก่ DOM ของคอลเลกชัน NodeList และอาร์กิวเมนต์ pseudo-array ที่พร้อมใช้งานภายในฟังก์ชัน/วิธีการใดๆ

1. การใช้วิธีการวนซ้ำอาร์เรย์จริง

อย่างน้อยที่สุด ส่วนใหญ่ หรือทั้งหมด ถ้าไม่ใช่ทั้งหมด วิธีการวนซ้ำบนอาร์เรย์จริงสามารถใช้เพื่อวนซ้ำบนวัตถุที่มีลักษณะคล้ายอาร์เรย์

โครงสร้าง for และ for...in สามารถนำไปใช้กับอ็อบเจ็กต์ที่มีลักษณะคล้ายอาร์เรย์ได้ในลักษณะเดียวกับที่ใช้กับอาร์เรย์จริง

forEach และเมธอด Array.prototype อื่นๆ ยังใช้กับอ็อบเจ็กต์ที่มีลักษณะคล้ายอาร์เรย์ด้วย ในการดำเนินการนี้ คุณต้องใช้ Function.call หรือ Function.apply

ตัวอย่างเช่น หากคุณต้องการใช้ forEach กับคุณสมบัติ childNodes ของออบเจ็กต์ Node คุณจะทำดังนี้:

Array.prototype.forEach.call(node.childNodes, function(child) ( // ทำบางสิ่งกับวัตถุลูก));

เพื่อให้เคล็ดลับนี้ง่ายต่อการนำมาใช้ซ้ำ คุณสามารถประกาศการอ้างอิงถึงเมธอด Array.prototype.forEach ในตัวแปรแยกต่างหากและใช้เป็นทางลัดได้:

// (สมมติว่าโค้ดด้านล่างทั้งหมดอยู่ในขอบเขตเดียวกัน) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // ทำบางสิ่งกับวัตถุลูก));

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

2. แปลงเป็นอาร์เรย์จริง

ยังมีอีกวิธีที่ง่ายมากในการวนซ้ำอ็อบเจ็กต์ที่มีลักษณะคล้ายอาเรย์: แปลงให้เป็นอาเรย์จริง และใช้วิธีการใดๆ ที่กล่าวถึงข้างต้นเพื่อวนซ้ำอาเรย์จริง สำหรับการแปลง คุณสามารถใช้เมธอด Array.prototype.slice ทั่วไป ซึ่งสามารถนำไปใช้กับออบเจ็กต์ที่มีลักษณะคล้ายอาร์เรย์ใดๆ ได้ ซึ่งทำได้ง่ายมาก ดังแสดงในตัวอย่างด้านล่าง:

Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);

ตัวอย่างเช่น หากคุณต้องการแปลงคอลเลกชัน NodeList เป็นอาร์เรย์จริง คุณจะต้องมีโค้ดดังนี้:

Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);

3. หมายเหตุเกี่ยวกับออบเจ็กต์รันไทม์

หากคุณใช้วิธี Array.prototype กับออบเจ็กต์รันไทม์ (เช่น คอลเลกชัน DOM) คุณควรทราบว่าวิธีการเหล่านี้ไม่รับประกันว่าจะทำงานได้อย่างถูกต้องในสภาพแวดล้อมรันไทม์ทั้งหมด (รวมถึงเบราว์เซอร์) ขึ้นอยู่กับพฤติกรรมของออบเจ็กต์เฉพาะในสภาพแวดล้อมการดำเนินการเฉพาะ หรืออย่างแม่นยำมากขึ้นเกี่ยวกับวิธีการใช้งาน HasProperty การดำเนินการนามธรรมในออบเจ็กต์นี้ ปัญหาคือว่ามาตรฐาน ES5 เองอนุญาตให้มีความเป็นไปได้ที่วัตถุจะทำงานผิดปกติเกี่ยวกับการดำเนินการนี้ (ดู§8.6.2)

ดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องทดสอบการทำงานของเมธอด Array.prototype ในแต่ละสภาพแวดล้อมรันไทม์ (เบราว์เซอร์) ที่คุณวางแผนจะใช้แอปพลิเคชันของคุณ