2015-02-26 5 views
38

Как сделать итератор из класса ES6 таким же образом, как синтаксис JS1.7 SomeClass.prototype.__iterator__ = function() {...}?Как сделать итератор из класса ES6

[EDIT 16:00]

следующие работы:

class SomeClass { 
    constructor() { 
    } 

    *[Symbol.iterator]() { 
     yield '1'; 
     yield '2'; 
    } 

    //*generator() { 
    //} 

} 

an_instance = new SomeClass(); 
for (let v of an_instance) { 
    console.log(v); 
} 

WebStorm флаги *[Symbol.iterator]() с «именем функции ожидаемого» предупреждение непосредственно после Астерикс, но в остальном это компилируется и работает нормально с трейсер , (Примечание WebStorm не создает каких-либо ошибок для *generator().)

+0

Этот код отлично подходит для меня в узле 'v8.1.1' –

ответ

19

Определите подходящий метод итератора. Например:

class C { 
    constructor() { this.a = [] } 
    add(x) { this.a.push(x) } 
    [Symbol.iterator]() { return this.a.values() } 
} 

Edit: Использование Пример:

let c = new C 
c.add(1); c.add(2) 
for (let i of c) console.log(i) 
+0

И префикс со звездочкой для использования в качестве функции генератора по внешнему виду. – user5321531

+8

В этом конкретном примере не используется генератор. Это просто делегирование итератора массива. –

+0

Не могли бы вы привести пример использования этого кода? Я не могу заставить его работать. – timkay

18

Вы должны указать Symbol.iterator свойство для SomeClass, который возвращает iterator для экземпляров класса. Итератор должен иметь метод next(), ведьма в свою очередь возвращает объект с полями done и value. Упрощенный пример:

function SomeClass() { 
    this._data = [1,2,3,4]; 
} 

SomeClass.prototype[Symbol.iterator] = function() { 
    var index = 0; 
    var data = this._data; 

    return { 
    next: function() { 
     return { value: data[++index], done: !(index in data) } 
    } 
    }; 
}; 

Или с помощью классов ES6 и стрелками функции:

class SomeClass { 
    constructor() { 
    this._data = [1,2,3,4]; 
    } 

    [Symbol.iterator]() { 
    var index = -1; 
    var data = this._data; 

    return { 
     next:() => ({ value: data[++index], done: !(index in data) }) 
    }; 
    }; 
} 

и использование:

var obj = new SomeClass(); 
for (var i of obj) { console.log(i) } 

в вашем обновленном вопросе вы поняли класс итератор через функции генератора , Вы можете это сделать, но вы должны понимать, что итератор НЕ МОЖЕТ быть генератором. На самом деле итератором в es6 является любой объект, который имеет конкретный next() method

+0

См. Редактирование исходного вопроса. – user5321531

+0

Это действительно работает, лучше, чем ответ помечен как правильный. Благодаря! –

9

Вот пример итерации по 2D-матрицы пользовательского класса в ES6

class Matrix { 
    constructor() { 
     this.matrix = [[1, 2, 9], 
         [5, 3, 8], 
         [4, 6, 7]]; 
    } 

    *[Symbol.iterator]() { 
     for (let row of this.matrix) { 
      for (let cell of row) { 
       yield cell; 
      } 
     } 
    } 
} 

Использование такого класса будет

let matrix = new Matrix(); 

for (let cell of matrix) { 
    console.log(cell) 
} 

Какой у вас Выход ЛД

1 
2 
9 
5 
3 
8 
4 
6 
7 
+0

Примечание. Для выполнения вышеуказанного кода может потребоваться последняя версия nodeJS. Он компилируется с использованием 'node v8.1.1' –

+2

. Вы можете упростить итератор, используя' for ... of' loops: 'for (let row this.matrix) {для (пусть ячейка строки) {yield cell; }} ' –

+1

@LukeMWillis - Ницца! Намного лучше. Обновленный ответ –

6

Документация: Iteration Protocols

Пример реализации класса как протоколитератора и Iterable протокола техники:

class MyCollection { 
    constructor(elements) { 
    if (!Array.isArray(elements)) 
     throw new Error('Parameter to constructor must be array'); 

    this.elements = elements; 
    } 

    // Implement "iterator protocol" 
    *iterator() { 
    for (let key in this.elements) { 
     var value = this.elements[key]; 
     yield value; 
    } 
    } 

    // Implement "iterable protocol" 
    [Symbol.iterator]() { 
    return this.iterator(); 
    } 
} 

элементы доступа с использованием либо метод:

var myCollection = new MyCollection(['foo', 'bar', 'bah', 'bat']); 

// Access elements of the collection using iterable 
for (let element of myCollection) 
    console.log('element via "iterable": ' + element); 

// Access elements of the collection using iterator 
var iterator = myCollection.iterator(); 
while (element = iterator.next().value) 
    console.log('element via "iterator": ' + element);