JavaScript ES6'da, yinelenebilir ve yineleyici arasındaki fark nedir?


14

Yinelenebilir bir yineleyici ile aynı mıdır yoksa farklı mıdır?

Spesifikasyonlardan , yinelenebilir bir nesne, objörneğin obj[Symbol.iterator]bir işleve atıfta bulunacak şekilde bir nesne gibi görünüyor, böylece çağrıldığında bir nesneyi nextdöndürebilecek bir yöntemi olan bir nesneyi döndürüyor {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)

Yani yukarıdaki kodda bar, yinelenebilir ve wahyineleyici ve next()yineleyici arabirimi.

Yani, yinelenebilir ve yineleyici farklı şeylerdir.

Ancak şimdi, yaygın bir jeneratör ve yineleyici örneğinde:

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

Yukarıdaki durumda gen1, jeneratör ve iter1yineleyici ve iter1.next()uygun işi yapacak. Ancak iter1[Symbol.iterator], çağrıldığında, iter1bir yineleyici olan bir işlev verir . Peki iter1bu durumda hem yinelenebilir hem de yineleyici midir?

Ayrıca, iter1örnek 1'de verebilir iterable çünkü yukarıdaki örnekte 1 farklıdır [1, 3, 5]kullanılarak istediği kadar çok kez [...bar]ederken, iter1bir iterable, ama aynı yineleyici her zaman olduğu kendisini döndüren beri, sadece verecektir [1, 3, 5]kez.

Dolayısıyla, yinelenebilir bir şekilde, sonucu barkaç kez verebileceğini söyleyebiliriz - ve cevap, duruma bağlıdır. Ve yineleyici bir yineleyici ile aynı mı? Ve cevap, farklı şeylerdir, ancak yinelenebilir kendini yineleyici olarak kullandığında aynı olabilirler. Bu doğru mu?[...bar][1, 3, 5]



" Peki iter1bu durumda hem yinelenebilir hem de yineleyici? " - evet. Tüm yerel yineleyiciler de geri dönerek yinelenebilir, böylece bunları yinelenebilir bir yapı bekleyen yapılara kolayca aktarabilirsiniz.
Bergi

Yanıtlar:


10

Evet, Iterables ve yineleyiciler farklı şeylerdir, ancak (örneğin itibaren JavaScript kendisinden almak olanlardan tümü dahil, çoğu yineleyiciler keysveya valuesüzerinde yöntemlerle Array.prototypeelde inherit jeneratör işlevlerden veya jeneratörler) % IteratorPrototype% nesnesi bir sahiptir, Symbol.iteratorgibi yöntem bu:

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

Sonuç tüm standart yineleyicilerin de yinelenebilir olmasıdır. Bu, onları doğrudan kullanabilir veya for-ofdöngülerde ve benzerlerinde kullanabilirsiniz (yineleyicileri değil, yineleyicileri bekler).

keysDizilerin yöntemini düşünün : Dizinin anahtarlarını ziyaret eden bir dizi yineleyicisi döndürür (dizinleri, sayı olarak). Bir yineleyici döndürdüğünü unutmayın . Ancak yaygın bir kullanımı:

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

for-ofBir sürer iterable değil, bir yineleyici , neden işliyor?

İşleyici çünkü yineleyici de tekrarlanabilir; Symbol.iteratorsadece geri döner this.

İşte kitabımın 6. Bölümünde kullandığım bir örnek: Tüm girişler arasında geçiş yapmak istiyor ancak ilkini atlamak istiyorsanız sliceve alt kümeyi dilimlemek için kullanmak istemiyorsanız , yineleyiciyi alabilir, ilk değeri okuyabilirsiniz, sonra bir for-ofdöngüye verin:

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

Bunun tüm standart yineleyiciler olduğunu unutmayın . Bazen insanlar böyle manuel olarak kodlanmış yineleyicilere örnekler gösterir:

rangeOrada döndürülen yineleyici bir yinelenebilir değildir , bu yüzden onu kullanmaya çalıştığımızda başarısız olur for-of.

Tekrarlanabilir hale getirmek için şunlardan birini yapmamız gerekir:

  1. Symbol.iteratorYöntemi yukarıdaki cevabın başına ekleyin veya
  2. Bu yöntemi zaten içeren% IteratorPrototype% kaynağından devralmasını sağlayın

Ne yazık ki, TC39% IteratorPrototype% nesnesini elde etmek için doğrudan bir yol sunmamaya karar verdi. Dolaylı bir yol var (bir diziden yineleyici almak, sonra% IteratorPrototype% olarak tanımlanan prototipini almak), ancak bu bir acı.

Ancak yineleyicileri böyle bir şekilde elle yazmaya gerek yoktur; sadece bir jeneratör işlevi kullanın, çünkü döndürdüğü jeneratör tekrarlanabilir:


Buna karşılık, tüm yinelenebilirler yineleyiciler değildir. Diziler yinelenebilir, ancak yineleyiciler değildir. Dizeler, Haritalar ve Kümeler de öyle.


0

Terimlerin daha kesin tanımlarının olduğunu ve bunların daha kesin cevaplar olduğunu buldum:

Göre ES6 Teknik Özellikleri ve MDN'yi :

Elimizde

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

foojeneratör fonksiyonu denir . Ve sonra elimizde

let bar = foo();

barbir jeneratör nesnesidir . Ve bir jeneratör nesnesi hem tekrarlanabilir protokole hem de iteratör protokolüne uygundur .

Daha basit sürüm, sadece bir .next()yöntem olan yineleyici arabirimidir .

Yinelenebilir protokol: nesne için obj, obj[Symbol.iterator]"yineleyici protokolüne uygun bir nesne döndüren sıfır bağımsız değişkenler işlevi" verir.

By MDN bağlantı başlığı , aynı zamanda biz de sadece jeneratör bir "jeneratör" nesne çağırabilir görünüyor.

O Not ECMAScript 6 Anlamak Nicolas Zakas kitabında , muhtemelen gevşek bir "jeneratör" olarak, bir "oluşturucu işlev" denir ve bir "Yineleyici" gibi bir "jeneratör nesne". Alma noktası, her ikisi de gerçekten "jeneratör" ile ilgilidir - biri bir jeneratör fonksiyonu ve diğeri bir jeneratör nesnesi veya jeneratördür. Jeneratör nesnesi, hem yinelenebilir protokole hem de yineleyici protokolüne uygundur.

O uyan sadece bir obje ise yineleyici protokolü, sen olamaz kullanmak [...iter]veya for (a of iter). Yinelenebilir protokole uyan bir nesne olmalıdır .

Ve sonra, bir taslakta olan gelecekteki JavaScript özelliklerinde yeni bir Iterator sınıfı da var . Bu gibi yöntemler de dahil olmak daha büyük bir arayüze sahiptir forEach, map, reduceşimdiki Dizi arayüzüne ve bu gibi yenilerinin ait takeve drop. Geçerli yineleyici yalnızca nextarabirime sahip nesneye başvurur .

Özgün soruyu cevaplamak için: bir yineleyici ve bir iterable arasındaki farkın ne, cevap: Bir yineleyici arayüzü ile bir nesnedir .next()ve bir iterable bir nesnedir objböyle obj[Symbol.iterator]sıfır argüman fonksiyonunu verebileceği, çağrıldığında, bir yineleyici döndürür.

Ve bir jeneratör buna eklemek için hem tekrarlanabilir hem de yineleyicidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.