Dieser Artikel bietet Ihnen eine Einführung in die Prinzipien von Iteratoren und iterierbaren Objekten in ES6 (mit Beispielen). Ich hoffe, dass er Ihnen weiterhilft.
Die neuen Array-Methoden, Sammlungen, for-of-Schleifen, Spread-Operatoren (...) und sogar die asynchrone Programmierung von ES6 basieren alle auf der Implementierung eines Iterators (Iterator). In diesem Artikel werden die Iteratoren und Generatoren von ES6 ausführlich erläutert und die internen Prinzipien und die Verwendung iterierbarer Objekte weiter untersucht
Das Prinzip von Iteratoren
Verarbeitung von Arrays in Programmiersprachen Wenn Sie eine Schleifenanweisung oder eine Sammlung verwenden, müssen Sie eine Variable initialisieren, um die Iterationsposition aufzuzeichnen. Die programmgesteuerte Verwendung von Iteratoren kann diese Datenoperation vereinfachen.Wie entwerfe ich einen Iterator?
Der Iterator selbst ist ein Objekt. Dieses Objekt verfügt über die next()-Methode, um das Ergebnisobjekt zurückzugeben. Dieses Ergebnisobjekt verfügt über den nächsten Rückgabewert und den booleschen Abschlusswert der Iteration, der das simuliert Erstellung eines einfachen Iterators wie folgt:
Wennfunction createIterator(iterms) { let i = 0 return { next() { let done = (i >= iterms.length) let value = !done ? iterms[i++] : undefined return { done, value } } } } let arrayIterator = createIterator([1, 2, 3]) console.log(arrayIterator.next()) // { done: false, value: 1 } console.log(arrayIterator.next()) // { done: false, value: 2 } console.log(arrayIterator.next()) // { done: false, value: 3 } console.log(arrayIterator.next()) // { done: true, value: undefined }
Jedes Mal, wenn next() des Iterators aufgerufen wird, wird das nächste Objekt zurückgegeben, bis der Datensatz erschöpft ist.
Die Regeln zum Schreiben von Iteratoren in ES6 sind ähnlich, aber es werden Generatorobjekte eingeführt, um das Erstellen von Iteratorobjekten zu erleichtern
2. Erstellen Sie Iteratoren
ES6 kapselt einen Generator zum Erstellen von Iteratoren. Offensichtlich ist ein Generator eine Funktion, die einen Iterator zurückgibt, der durch ein Sternchen (*) nach der Funktion dargestellt wird, und das neue interne Sonderschlüsselwort yield verwendet, um den Rückgabewert der next()-Methode des Iterators anzugeben.
Wie erstelle ich einen Iterator mit ES6-Generatoren? Ein einfaches Beispiel lautet wie folgt:
function *createIterator() { yield 123; yield 'someValue' } let someIterator = createIterator() console.log(someIterator.next()) // { value: 123, done: false } console.log(someIterator.next()) // { value: 'someValue', done: false } console.log(someIterator.next()) // { value: undefined, done: true }
Mit dem Schlüsselwort yield können Sie jeden Wert oder Ausdruck zurückgeben und Elemente stapelweise zum Iterator hinzufügen:
// let createIterator = function *(items) { // 生成器函数表达式 function *createIterator(items) { for (let i = 0; i < items.length; i++) { yield items[i] } } let someIterator = createIterator([123, 'someValue']) console.log(someIterator.next()) // { value: 123, done: false } console.log(someIterator.next()) // { value: 'someValue', done: false } console.log(someIterator.next()) // { value: undefined, done: true }
Da es sich um den Generator selbst handelt Als Funktion kann sie dem Objekt hinzugefügt werden und wird wie folgt verwendet:
Eine Funktion derlet obj = { // createIterator: function *(items) { // ES5 *createIterator(items) { // ES6 for (let i = 0; i < items.length; i++) { yield items[i] } } } let someIterator = obj.createIterator([123, 'someValue'])
3. Iterierbare Objekte
Häufig verwendete Sammlungsobjekte (Arrays, Set/Map-Sammlungen) und Strings in ES6 sind iterierbare Objekte, und diese Objekte verfügen über Standard-Iteratoren und den Symbol.iterator Eigentum.
Durch Generatoren erstellte Iteratoren sind ebenfalls iterierbare Objekte, da Generatoren der Eigenschaft Symbol.iterator standardmäßig Werte zuweisen.
3.1 Symbol.iterator
Iterierbare Objekte haben die Eigenschaft Symbol.iterator, d. h. Objekte mit der Eigenschaft Symbol.iterator haben Standarditeratoren.
Wir können Symbol.iterator verwenden, um auf den Standarditerator eines Objekts zuzugreifen, beispielsweise für ein Array:
let list = [11, 22, 33] let iterator = list[Symbol.iterator]() console.log(iterator.next()) // { value: 11, done: false }
Symbol.iterator ruft den Standarditerator des iterierbaren Objekts des Arrays ab und bearbeitet es. Iteriert über die Elemente im Array.
Im Gegenteil, wir können Symbol.iterator verwenden, um zu erkennen, ob das Objekt ein iterierbares Objekt ist:
function isIterator(obj) { return typeof obj[Symbol.iterator] === 'function' } console.log(isIterator([11, 22, 33])) // true console.log(isIterator('sometring')) // true console.log(isIterator(new Map())) // true console.log(isIterator(new Set())) // true console.log(isIterator(new WeakMap())) // false console.log(isIterator(new WeakSet())) // false
Offensichtlich sind Arrays, Set/Map-Sammlungen und Strings alle iterierbare Objekte und WeakSet /WeakMap-Sammlungen (schwache Referenzsammlungen) sind nicht iterierbar.
3.2 Iterierbare Objekte erstellen
Benutzerdefinierte Objekte sind standardmäßig nicht iterierbar.
Wie gerade erwähnt, ist der durch den Generator erstellte Iterator auch ein iterierbares Objekt. Der Generator weist der Eigenschaft Symbol.iterator standardmäßig einen Wert zu.
Wie kann man also ein benutzerdefiniertes Objekt in ein iterierbares Objekt umwandeln? Durch Hinzufügen eines Generators zur Eigenschaft Symbol.iterator:
let collection = { items: [11,22,33], *[Symbol.iterator]() { for (let item of this.items){ yield item } } } console.log(isIterator(collection)) // true for (let item of collection){ console.log(item) // 11 22 33 }
Die Array-Elemente sind ein iterierbares Objekt, und das Sammlungsobjekt wird ebenfalls zu einem iterierbaren Objekt, indem der Eigenschaft Symbol.iterator ein Wert zugewiesen wird.
3.3 for-of
Beachten Sie, dass das letzte Beispiel for-of anstelle der Indexschleife verwendet, eine neue Funktion, die von ES6 für iterierbare Objekte hinzugefügt wurde.
Denken Sie über das Implementierungsprinzip der For-Of-Schleife nach.
Für iterierbare Objekte, die for-of verwenden, wird jedes Mal, wenn for-of ausgeführt wird, next() des iterierbaren Objekts aufgerufen und das Rückgabeergebnis in einer Variablen gespeichert. Die Ausführung wird bis zum fortgesetzt iterierbares Objekt Der Wert des done-Attributs ist falsch.
// 迭代一个字符串 let str = 'somestring' for (let item of str){ console.log(item) // s o m e s t r i n g }
Im Wesentlichen ruft for-of die Attributmethode Symbol.iterator der Zeichenfolge str auf, um den Iterator zu erhalten (dieser Vorgang wird von der JS-Engine abgeschlossen) und ruft dann zum Speichern mehrmals die Methode next() auf der Objektwert in der Elementvariablen.
Die Verwendung von for-of für nicht iterierbare Objekte, null oder undefiniert, meldet einen Fehler!3.4 Spread-Operator (...)
Der ES6-Syntax-Zucker-Spread-Operator (...) bedient auch iterierbare Objekte, das heißt, er kann nur Arrays und Sammlungen „verteilen“. , Strings, benutzerdefinierte iterierbare Objekte.
Die folgende Kastanie gibt die von verschiedenen iterierbaren Objekterweiterungsoperatoren berechneten Ergebnisse aus:
let str = 'somestring' console.log(...str) // s o m e s t r i n g let set = new Set([1, 2, 2, 5, 8, 8, 8, 9]) console.log(set) // Set { 1, 2, 5, 8, 9 } console.log(...set) // 1 2 5 8 9 let map = new Map([['name', 'jenny'], ['id', 123]]) console.log(map) // Map { 'name' => 'jenny', 'id' => 123 } console.log(...map) // [ 'name', 'jenny' ] [ 'id', 123 ] let num1 = [1, 2, 3], num2 = [7, 8, 9] console.log([...num1, ...num2]) // [ 1, 2, 3, 7, 8, 9 ] let udf console.log(...udf) // TypeError: undefined is not iterable
Wie aus dem obigen Code ersichtlich ist, kann der Erweiterungsoperator (...) iterierbare Objekte bequem konvertieren ein Array. Wie for-of meldet der Spread-Operator (...) einen Fehler, wenn er auf nicht iterierbare Objekte, null oder undefiniert, angewendet wird!
4. Standard-Iterator
ES6 为很多内置对象提供了默认的迭代器,只有当内建的迭代器不能满足需求时才自己创建迭代器。
ES6 的 三个集合对象:Set、Map、Array 都有默认的迭代器,常用的如values()方法、entries()方法都返回一个迭代器,其值区别如下:
entries():多个键值对
values():集合的值
keys():集合的键
调用以上方法都可以得到集合的迭代器,并使用for-of循环,示例如下:
/******** Map ***********/ let map = new Map([['name', 'jenny'], ['id', 123]]) for(let item of map.entries()){ console.log(item) // [ 'name', 'jenny' ] [ 'id', 123 ] } for(let item of map.keys()){ console.log(item) // name id } for (let item of map.values()) { console.log(item) // jenny 123 } /******** Set ***********/ let set = new Set([1, 4, 4, 5, 5, 5, 6, 6,]) for(let item of set.entries()){ console.log(item) // [ 1, 1 ] [ 4, 4 ] [ 5, 5 ] [ 6, 6 ] } /********* Array **********/ let array = [11, 22, 33] for(let item of array.entries()){ console.log(item) // [ 0, 11 ] [ 1, 22 ] [ 2, 33 ] }
此外 String 和 NodeList 类型都有默认的迭代器,虽然没有提供其它的方法,但可以用for-of循环
Das obige ist der detaillierte Inhalt vonEinführung in die Prinzipien von Iteratoren und iterierbaren Objekten in ES6 (mit Beispielen). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!