web-dev-qa-db-ja.com

ES6クラスからイテレーターを作成する方法

JS1.7 SomeClass.prototype.__iterator__ = function() {...}構文と同じ方法でES6クラスからイテレーターを作成するにはどうすればよいですか?

[編集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]()にフラグを立て、アスタリスクの直後に「関数名が必要です」という警告を表示しますが、そうでない場合はTraceurでコンパイルおよび実行できます。 (注WebStormは*generator()に対してエラーを生成しません。)

56
user5321531

適切なイテレータメソッドを定義します。例えば:

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

編集:サンプル使用:

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

クラスインスタンスに対して iterator を返すSomeClassに対して_Symbol.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) }
_

更新された質問で、クラスiteratorからgenerator functionを実現しました。そうすることはできますが、イテレーターはジェネレーターではないことを理解する必要があります。実際、es6のイテレーターは、特定の next() method を持つオブジェクトです。

32
alexpods

ES6で2Dマトリックスのカスタムクラスを反復処理する例を次に示します

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
20
Shaheen Ghiassy

ドキュメント: 反復プロトコル

iterator protocoliterable protocolの両方のテクニックを実装するクラスの例:

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);
11
ekillaby

サブオブジェクトに格納するES6イテレータークラスの例:

class Iterator {
    data;

    constructor(data = {}) {
        this.data = JSON.parse(JSON.stringify(data));
    }

    add(key, value) { this.data[key] = value; }

    get(key) { return this.data[key]; }

    [Symbol.iterator]() {
        const keys = Object.keys(this.data).filter(key => 
        this.data.hasOwnProperty(key));
        const values = keys.map(key => this.data[key]).values();
        return values;
    }
}
0
kyleo347

説明

オブジェクトを作成するiterableは、このオブジェクトにSymbol.iteratorという名前のメソッドがあることを意味します。このメソッドが呼び出されると、iteratorと呼ばれるインターフェースを返す必要があります。

このイテレータには、次の結果を返すメソッドnextが必要です。この結果は、次の値を提供するvalueプロパティと、それ以上結果がない場合はdoneであり、それ以外の場合はtrueであるfalseプロパティを持つオブジェクトでなければなりません。 。

実装

また、すべての要素が0からwidth * height - 1に及ぶMatrixというクラスのイテレーターも実装します。このイテレーターにMatrixIteratorと呼ばれる別のクラスを作成します。

class Matrix {
    constructor(width, height) {
        this.width = width;
        this.height = height;
        this.content = [];

        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                this.content[y * width + x] = y * width + x;
            }
        }
    }

    get(x, y) {
        return this.content[y * this.width + x];
    }

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


class MatrixIterator {
    constructor(matrix) {
        this.x = 0;
        this.y = 0;
        this.matrix = matrix;
    }

    next() {
        if (this.y == this.matrix.height) return {done: true};

        let value = {
            x: this.x,
            y: this.y,
            value: this.matrix.get(this.x, this.y)
        };

        this.x++;

        if (this.x == this.matrix.width) {
            this.x = 0;
            this.y++;
        }

        return {value, done: false};
    }
}

Matrixは、Symbol.iteratorシンボルを定義することでiteratorプロトコルを実装することに注意してください。このメソッド内で、MatrixIteratorのインスタンスが作成されます。このインスタンスはthis、つまりMatrixインスタンスをパラメーターとして受け取り、MatrixIteratorの内部でメソッドnextは定義済み。 iteratorSymbol.iteratorの実装が明確に示されているため、このイテレータの実装方法が特に気に入っています。

または、次のようにSymbol.iteratorを直接定義せずに、prototype[Symbol.iterator]に関数を追加することもできます。

Matrix.prototype[Symbol.iterator] = function() {
    return new MatrixIterator(this);
};

使用例

let matrix = new Matrix(3, 2);
for (let e of matrix) {
    console.log(e);
}
0
lmiguelvargasf