wake-up-neo.net

Wie man einen Iterator aus einer ES6-Klasse macht

Wie würde ich einen Iterator aus einer ES6-Klasse auf dieselbe Weise wie JS1.7 SomeClass.prototype.__iterator__ = function() {...}-Syntax erstellen?

[EDIT 16:00]

Die folgenden Arbeiten:

class SomeClass {
    constructor() {
    }

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

    //*generator() {
    //}

}

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

WebStorm kennzeichnet *[Symbol.iterator]() mit der Warnung 'Funktionsname erwartet' direkt nach dem Stern, dies wird jedoch ansonsten mit Traceur kompiliert. (Hinweis: WebStorm generiert für *generator() keine Fehler.)

50
user5321531

Definieren Sie eine geeignete Iteratormethode. Zum Beispiel:

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

Bearbeiten: Verwendungsbeispiel:

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

Sie müssen die Symbol.iterator-Eigenschaft für SomeClass angeben, die iterator für Klasseninstanzen zurückgibt. Iterator muss die next()-Methode haben, die wiederum das Objekt mit den done- und value-Feldern zurückgibt. Vereinfachtes Beispiel:

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

Oder mit ES6-Klassen und Pfeilfunktionen:

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

Und Verwendung:

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

In Ihrer aktualisierten Frage haben Sie die Klasse iterator durch generator function realisiert. Sie können dies tun, aber Sie müssen verstehen, dass der Iterator KEIN Generator sein KANN. Tatsächlich ist der Iterator in es6 jedes Objekt, das eine bestimmte next()-Methode hat

27
alexpods

Hier ein Beispiel für das Durchlaufen einer benutzerdefinierten 2D-Matrixklasse in 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;
            }
        }
    }
}

Die Verwendung einer solchen Klasse wäre

let matrix = new Matrix();

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

Was würde ausgeben

1
2
9
5
3
8
4
6
7
18
Shaheen Ghiassy

Dokumentation: Iterationsprotokolle

Beispielklasse, die die Techniken iterator protocol und iterable protocol implementiert:

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

Greifen Sie auf Elemente mit einer der beiden Methoden zu:

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

Beispiel einer ES6-Iteratorklasse, die in einem Unterobjekt gespeichert wird:

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

Erläuterung

Wenn Sie ein Objekt iterabel machen, hat dieses Objekt eine Methode mit dem Namen Symbol.iterator. Wenn diese Methode aufgerufen wird, sollte sie eine Schnittstelle mit dem Namen iterator zurückgeben.

Dieser Iterator muss eine Methode next haben, die das nächste Ergebnis zurückgibt. Dieses Ergebnis sollte ein Objekt mit einer value -Eigenschaft sein, die den nächsten Wert bereitstellt, und eine done -Eigenschaft, die true sein sollte, wenn keine Ergebnisse mehr vorliegen, und false andernfalls.

Implementierung

Ich werde auch einen Iterator für eine Klasse namens Matrix implementieren, dessen Elemente von 0 bis width * height - 1 reichen. Ich werde eine andere Klasse für diesen Iterator namens MatrixIterator erstellen.

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

Beachten Sie, dass Matrix das Protokoll iterator implementiert, indem Sie das Symbol Symbol.iterator definieren. Innerhalb dieser Methode wird eine Instanz von MatrixIterator erstellt, die this, d. H. Die Matrix -Instanz, als Parameter verwendet, und innerhalb von MatrixIterator wird die Methode next definiert. Ich mag diese Art der Implementierung eines Iterators besonders, weil sie den Iterator und die Implementierung des Symbol.iterator deutlich zeigt.

Alternativ kann man auch nicht direkt Symbol.iterator definieren und stattdessen eine Funktion wie folgt zu prototype[Symbol.iterator] hinzufügen:

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

Anwendungsbeispiel

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