JavaScript/Objekte/Map/iterator
Die Eigenschaft, deren Schlüssel das Symbol @@iterator
ist, definiert die Standardschnittstelle für die Iteration von Maps. Ihr Wert ist standardmäßig eine Referenz auf die Mapmethode entries. In einem Iterationskontext wird diese Methode implizit aufgerufen, wenn kein Iterator übergeben wurde.
Syntax
Map.prototype[Symbol.iterator]( )
Beschreibung
Eingebaute Strukturen, wie beispielsweise eine Schleife mit for und of oder auch der Konstruktor Map, die nach dem spezifizierten Protokoll für die Iteration arbeiten, erwarten als Argument einen Iterator. Wird ihnen hingegen ein Objekt übergeben, welches die Iteratorschnittstelle nicht implementiert hat, dann wird intern geprüft, ob auf dem Objekt selbst oder auf einem seiner Prototypen eine Standardschnittstelle für die Iteration definiert ist.
function isIterable (object) {
return typeof object[Symbol.iterator] === 'function';
}
const map = new Map;
console.log(isIterable(map)); // true
Die Standardschnittstelle für die Iteration ist dabei als Eigenschaft definiert, deren Schlüssel das Symbol @@iterator ist. Diese eingebaute Konstante ist der Wert der Eigenschaft iterator des Objektes Symbol. Bei dem Wert der Eigenschaft, welche die Standardschnittstelle definiert, muss es sich um eine Funktion handeln, deren Rückgabewert ein Iterator ist.
const defaultInterface = Map.prototype[Symbol.iterator];
console.log(defaultInterface === Map.prototype.entries); // true
Wie der Vergleich in dem Beispiel oben zeigt, ist bei Maps als Standardschnittstelle die Methode entries vorgesehen, die bei ihrem Aufruf einen Iterator zurückgibt, mit dem über die Einträge einer Map iteriert werden kann, der also sowohl die Schlüssel als auch die Werte der in der Map hinterlegten Einträge ausgibt.
const map = new Map([
['key', 'value']
]);
for (let entry of map) {
console.log(Array.isArray(entry)); // true
}
Soll also wie in diesem Beispiel über eine Map iteriert werden und wird dabei nur eine Referenz auf die Map übergeben, also kein Iteratorobjekt, dann wird intern nachgesehen, ob auf der Map selbst oder auf einem ihrer Prototypen eine Eigenschaft existiert, deren Schlüssel das Symbol @@iterator ist und deren Wert eine Funktion ist, die einen Iterator zurückgibt. Da wie gesehen auf dem Objekt Map.prototype eine solche Eigenschaft definiert ist, deren Wert eine Referenz auf die Methode entries ist, wird intern diese Methode aufgerufen und der von ihr zurückgegebene Iterator verwendet.
Selbstdefinierte Schnittstellen
Grundsätzlich ist es möglich, der Eigenschaft mit dem Schlüssel @@iterator einen anderen Wert zuzuweisen, also eine andere Methode als Standardschnittstelle für die Iteration von Maps zu bestimmen. Allerdings ist von einer solchen Manipulation in der Regel dringend abzuraten, da dies mit großer Wahrscheinlichkeit zu schwerwiegenden Fehlern führen wird, entweder in anderen Teilen desselben Programms oder aber in Programmen, die in Zukunft vielleicht noch eingebunden werden, und die sich darauf verlassen, dass standardmäßig die Methode entries aufgerufen wird.
class CustomMap extends Map {
[Symbol.iterator] ( ) {
return this.keys( );
}
}
const map = new CustomMap([
['key', 'value']
]);
for (let key of map) {
console.log(key); // key
}
Soll also eine andere Standardschnittstelle spezifiziert werden, dann sollte dies entweder durch Definition direkt auf den einzelnen Mapinstanzen bewerkstelligt werden, oder wie in dem Beispiel oben, indem eine von Map abgeleitete Klasse erzeugt wird, in deren Körper für die Eigenschaft mit dem Schlüssel @@iterator eine andere Methode definiert wird. Auf diese Weise kann für eine beliebige Zahl von Maps zum Beispiel bestimmt werden, dass bei der Iteration standardmäßig nur die Schlüssel ausgegeben werden sollen, ohne dass dabei das Risiko von Konflikten besteht.
Weblinks
- ECMAScript 2016: Map.prototype[@@iterator]
- MDN: Map.prototype[@@iterator]