ใน JavaScript ES6 ความแตกต่างระหว่างตัววนซ้ำกับตัววนซ้ำคืออะไร


14

iterable เหมือนกับ iterator หรือแตกต่างกันหรือไม่?

ดูเหมือนว่าจากข้อมูลจำเพาะ iterable เป็นวัตถุพูดobjเช่นนั้นobj[Symbol.iterator]หมายถึงฟังก์ชั่นเพื่อที่เมื่อถูกเรียกกลับวัตถุที่มีnextวิธีการที่จะกลับ{value: ___, done: ___}วัตถุ:

function foo() {
    let i = 0;
    const wah = {
        next: function() {
            if (i <= 2) return { value: (1 + 2 * i++), done: false }
            else return { value: undefined, done: true }
        }
    };
    return wah;     // wah is iterator
}

let bar = {}        // bar is iterable

bar[Symbol.iterator] = foo;

console.log([...bar]);             // [1, 3, 5]   
for (a of bar) console.log(a);     // 1 3 5 (in three lines)

ดังนั้นในโค้ดข้างต้นbarคือ iterable และwahเป็น iterator และ the next()คือ interface iterator

ดังนั้น iterable และ iterator จึงแตกต่างกัน

อย่างไรก็ตามในตัวอย่างทั่วไปของตัวกำเนิดและตัววนซ้ำ:

function* gen1() {
    yield 1;
    yield 3;
    yield 5;
}

const iter1 = gen1();

console.log([...iter1]);                           // [1, 3, 5]
for (a of iter1) console.log(a);                   // nothing

const iter2 = gen1();
for (a of iter2) console.log(a);                   // 1 3 5 (in three lines)

console.log(iter1[Symbol.iterator]() === iter1);   // true

ในกรณีข้างต้นgen1เป็นตัวกำเนิดและiter1เป็นตัววนซ้ำและiter1.next()จะทำงานที่เหมาะสม แต่iter1[Symbol.iterator]จะให้ฟังก์ชันที่เมื่อเรียกใช้จะให้กลับiter1ซึ่งเป็นตัววนซ้ำ ดังนั้นiter1ทั้ง iterable และ iterator ในกรณีนี้คืออะไร?

นอกจากนี้iter1จะแตกต่างจากตัวอย่างที่ 1 ข้างต้นเนื่องจากการทำซ้ำในตัวอย่างที่ 1 สามารถให้ได้[1, 3, 5]หลายครั้งตามที่ต้องการใช้[...bar]ในขณะที่iter1สามารถทำซ้ำได้ แต่เนื่องจากส่งคืนตัวเองซึ่งเป็นตัววนซ้ำเดียวกันทุกครั้งจะให้เพียง[1, 3, 5]ครั้งเดียว

ดังนั้นเราจึงสามารถพูดได้ว่าbarสามารถ[...bar]ให้ผลลัพธ์ได้กี่ครั้ง[1, 3, 5]และคำตอบก็คือ และ iterable เหมือนกับ iterator หรือไม่? และคำตอบก็คือพวกมันต่างกัน แต่ก็เหมือนกันเมื่อมันใช้ตัวมันเองเป็นตัววนซ้ำ ถูกต้องไหม


ที่เกี่ยวข้องอย่างใกล้ชิด: นิยามทางเทคนิคของ Javascript iterable คืออะไร
Bergi

" ดังนั้นiter1ทั้ง iterable และ iterator ในกรณีนี้คืออะไร " - ใช่ ตัววนซ้ำพื้นเมืองทั้งหมดสามารถทำซ้ำได้ด้วยการส่งคืนตัวเองเพื่อให้คุณสามารถส่งต่อไปยังสิ่งก่อสร้างที่คาดว่าจะทำซ้ำได้ง่าย
Bergi

ความซ้ำซ้อนที่เป็นไปได้ของIterator และ Iterable
Felix Kling

คำตอบ:


10

ใช่iterablesและiteratorsเป็นสิ่งที่แตกต่างกัน แต่ iterators (รวมถึงทุกคนที่คุณได้รับจากการใช้ JavaScript ในตัวเองเช่นจากkeysหรือvaluesวิธีการเกี่ยวกับArray.prototypeหรือเครื่องกำเนิดไฟฟ้าจากฟังก์ชั่นเครื่องกำเนิดไฟฟ้า) ที่สืบทอดจาก% IteratorPrototype% วัตถุซึ่งมีSymbol.iteratorวิธีการเช่น นี้:

[Symbol.iterator]() {
    return this;
}

ผลที่ได้คือตัววนซ้ำมาตรฐานทั้งหมดนั้นซ้ำอีกด้วย นั่นคือเพื่อให้คุณสามารถใช้พวกเขาโดยตรงหรือใช้พวกเขาในfor-ofลูปและเช่น (ซึ่งคาดว่า iterables ไม่ใช่ iterators)

พิจารณาkeysวิธีการของอาเรย์: มันจะคืนค่าตัววนซ้ำอาร์เรย์ที่เข้าชมคีย์ของอาเรย์ (ดัชนีของมันเป็นตัวเลข) โปรดทราบว่าจะส่งกลับiterator แต่การใช้งานทั่วไปของมันคือ:

for (const index of someArray.keys()) {
    // ...
}

for-ofใช้การวนซ้ำไม่ใช่ตัววนซ้ำดังนั้นทำไมจึงใช้งานได้

มันใช้งานได้เพราะตัววนซ้ำยังวนซ้ำได้ Symbol.iteratorเพิ่งกลับthisมา

นี่คือตัวอย่างที่ฉันใช้ในบทที่ 6 ของหนังสือของฉัน: หากคุณต้องการวนซ้ำรายการทั้งหมด แต่ข้ามรายการแรกและคุณไม่ต้องการใช้sliceเพื่อตัดส่วนย่อยคุณสามารถรับตัววนซ้ำอ่านค่าแรก จากนั้นส่งไปที่for-ofลูป:

const a = ["one", "two", "three", "four"];
const it = a[Symbol.iterator]();
// Skip the first one
it.next();
// Loop through the rest
for (const value of it) {
    console.log(value);
}

โปรดทราบว่านี่เป็นตัววนซ้ำมาตรฐานทั้งหมด บางครั้งผู้คนแสดงตัวอย่างของตัววนซ้ำแบบเข้ารหัสด้วยตนเองดังนี้:

iterator กลับโดยrangeมีไม่ iterable for-ofจึงล้มเหลวเมื่อเราพยายามที่จะใช้กับ

ในการทำให้ iterable เราต้อง:

  1. เพิ่มSymbol.iteratorวิธีการที่จุดเริ่มต้นของคำตอบข้างต้นหรือ
  2. ทำให้เป็นสืบทอดจาก% IteratorPrototype% ซึ่งมีวิธีการนั้นอยู่แล้ว

น่าเสียดายที่ TC39 ตัดสินใจที่จะไม่ให้วิธีการโดยตรงเพื่อรับออบเจ็กต์% IteratorPrototype% มีวิธีทางอ้อม (รับตัววนซ้ำจากอาร์เรย์จากนั้นนำต้นแบบซึ่งกำหนดให้เป็น% IteratorPrototype%) แต่มันเป็นความเจ็บปวด

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


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


0

ฉันพบว่ามีคำจำกัดความที่ชัดเจนยิ่งขึ้นและนี่คือคำตอบที่ชัดเจนยิ่งขึ้น:

ตามข้อกำหนด ES6และMDN :

เมื่อเรามี

function* foo() {   // note the "*"
    yield 1;
    yield 3;
    yield 5;
}

fooเรียกว่ากำเนิดฟังก์ชั่น และเมื่อเรามี

let bar = foo();

barเป็นเครื่องกำเนิดไฟฟ้าวัตถุ และกำเนิดวัตถุสอดทั้งโปรโตคอล iterable และโปรโตคอลการทำซ้ำโดย

เวอร์ชันที่ง่ายกว่าคืออินเทอร์เฟซตัววนซ้ำซึ่งเป็นเพียง.next()วิธีการ

โปรโตคอล iterable คือ: สำหรับวัตถุobj, obj[Symbol.iterator]ให้ "ศูนย์การขัดแย้งผลตอบแทนที่ทำงานว่าวัตถุที่สอดคล้องกับโพรโทคอ iterator ว่า"

ด้วยชื่อของลิงค์ MDNดูเหมือนว่าเราสามารถเรียกเครื่องมือกำเนิด "วัตถุ" ได้

โปรดทราบว่าในหนังสือของ Nicolas Zakas การทำความเข้าใจ ECMAScript 6เขาอาจเรียกว่า "ฟังก์ชันตัวสร้าง" เป็น "ตัวกำเนิด" และ "วัตถุตัวสร้าง" เป็น "ตัววนซ้ำ" จุดที่ต้องไปคือพวกมันมีทั้ง "generator" ที่เกี่ยวข้องกัน - อย่างใดอย่างหนึ่งคือฟังก์ชั่นเครื่องกำเนิดไฟฟ้าและหนึ่งคือวัตถุเครื่องกำเนิดไฟฟ้าหรือเครื่องกำเนิดไฟฟ้า วัตถุเครื่องกำเนิดสอดคล้องกับทั้งโปรโตคอล iteratable และโปรโตคอล iterator

ถ้ามันเป็นเพียงวัตถุที่สอดคล้องกับที่iteratorโปรโตคอลคุณไม่สามารถใช้หรือ[...iter] for (a of iter)มันจะต้องเป็นวัตถุที่สอดคล้องกับโปรโตคอลiterable

แล้วยังมีชั้น Iterator ใหม่ในอนาคตรายละเอียด JavaScript ที่ยังคงอยู่ในร่าง มีอินเตอร์เฟซที่มีขนาดใหญ่รวมทั้งวิธีการเช่นforEach, map, reduceของอินเตอร์เฟซอาร์เรย์ปัจจุบันและคนใหม่เช่นและและtake dropตัววนซ้ำปัจจุบันอ้างถึงวัตถุที่มีเพียงnextส่วนต่อประสาน

เพื่อตอบคำถามเดิม: อะไรคือความแตกต่างระหว่างตัววนซ้ำกับตัววนซ้ำคำตอบคือ: ตัววนซ้ำเป็นวัตถุที่มีส่วนต่อประสาน.next()และตัววนซ้ำนั้นเป็นวัตถุobjดังกล่าวที่obj[Symbol.iterator]สามารถให้ฟังก์ชันเป็นศูนย์โต้แย้งได้ ส่งคืนตัววนซ้ำ

และเครื่องกำเนิดไฟฟ้ามีทั้ง iterable และ iterator เพื่อเพิ่มเข้าไป

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