How to make an iterator out of an ES6 class

后端 未结 6 1155
挽巷
挽巷 2021-01-30 10:21

How would I make an iterator out of an ES6 class in the same manner as JS1.7 SomeClass.prototype.__iterator__ = function() {...} syntax?

[EDIT 16:00]

<
6条回答
  •  孤城傲影
    2021-01-30 10:54

    Explanation

    Making an object iterable means this object has a method named with the Symbol.iterator. When this method gets called, it should return an interface called iterator.

    This iterator must have a method next that returns the next result. This result should be an object with a value property that provides the next value, and a done property, which should be true when there are no more results and false otherwise.

    Implementation

    I will also implement an iterator for a class called Matrix which all elements will range from 0 to width * height - 1. I will create a different class for this iterator called 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};
        }
    }
    

    Notice that Matrix implements the iterator protocol by defining Symbol.iterator symbol. Inside this method, an instance of MatrixIterator is created which takes this, i.e., the Matrix instance as parameter, and inside MatrixIterator, the method next is defined. I particularly like this way of implementing an iterator because it clearly shows the iterator and the implementation of the Symbol.iterator.

    Alternatively, one can also not define directly Symbol.iterator, and instead add a function to prototype[Symbol.iterator] as follows:

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

    Usage Example

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

提交回复
热议问题