Cet article examinera la boucle for ... of
d'ES6.
Dans le passé, il y avait deux façons de parcourir javascript.
La première est la boucle classique for i
, qui vous permet de parcourir un tableau ou tout objet indexable et possédant une propriété length
.
for(i=0;i<things.length;i++) { var thing = things[i] /* ... */ }
Suivi de la boucle for ... in
, qui est utilisée pour parcourir les paires clé/valeur d'un objet. La boucle
for(key in things) { if(!thing.hasOwnProperty(key)) { continue; } var thing = things[key] /* ... */ }
for ... in
est souvent considérée comme un aparté car elle boucle sur chaque propriété énumérable de l'objet . Cela inclut les propriétés de l'objet parent dans la chaîne de prototypes, ainsi que toutes les propriétés affectées aux méthodes. En d’autres termes, cela passe par des choses auxquelles les gens ne s’attendaient pas. Utiliser for ... in
signifie généralement beaucoup de clauses de garde dans le bloc de boucle pour éviter les attributs indésirables.
Les premiers JavaScript ont résolu ce problème grâce aux bibliothèques. De nombreuses bibliothèques JavaScript (par exemple : Prototype.js, jQuery, lodash, etc.) ont des méthodes ou des fonctions utilitaires comme each
ou foreach
qui vous permettent de parcourir des objets et des tableaux sans for i
ou for ... in
.
for ... of
Les boucles sont le moyen utilisé par ES6 pour essayer de résoudre certains de ces problèmes sans bibliothèques tierces.
for ... of
boucle
for(const thing of things) { /* ... */ }
qui parcourra un objet itérable.
Un objet itérable est un objet qui définit la méthode @@ iterator, et la méthode @@iterator renvoie un objet qui implémente le protocole itérateur objet, ou la méthode est une fonction génératrice.
Il y a beaucoup de choses que vous devez comprendre dans cette phrase :
@@
?) Ce qui suit abordera ces questions une par une.
Tout d'abord, certains objets intégrés dans les objets JavaScript peuvent naturellement être itérés. Par exemple, le plus simple à penser est celui des objets tableau. Les tableaux peuvent être utilisés dans une boucle for ... of
comme dans le code suivant :
const foo = [ 'apples','oranges','pears' ] for(const thing of foo) { console.log(thing) }
Le résultat de sortie est tous les éléments du tableau.
apples oranges pears
Il existe également une méthode entries
pour les tableaux, qui renvoie un objet itérable. Cet itérable renvoie la clé et la valeur sur chaque boucle. Par exemple, le code suivant :
const foo = [ 'apples','oranges','pears' ] for(const thing of foo.entries()) { console.log(thing) }
affichera le
[ 0, 'apples' ] [ 1, 'oranges' ] [ 2, 'pears' ]
suivant. La méthode entries
sera plus utile lors de l'utilisation de la syntaxe suivante
const foo = [ 'apples','oranges','pears' ] for(const [key, value] of foo.entries()) { console.log(key,':',value) }
est déclarée dans un for boucle Deux variables : une pour renvoyer le premier élément du tableau (la clé ou l'index de la valeur), et une pour le deuxième élément (la valeur à laquelle correspond réellement l'index).
Un objet javascript normal n'est pas itérable. Si vous exécutez le code suivant :
// 无法正常执行 const foo = { 'apples':'oranges', 'pears':'prunes' } for(const [key, value] of foo) { console.log(key,':',value) }
vous obtiendrez une erreur
$ node test.js /path/to/test.js:6 for(const [key, value] of foo) { TypeError: foo is not iterable
Cependant la méthode statique de l'objet Object
globalentries
accepte un objet normal en tant que paramètre et renvoie un objet Iterable. Un programme comme celui-ci :
const foo = { 'apples':'oranges', 'pears':'prunes' } for(const [key, value] of Object.entries(foo)) { console.log(key,':',value) }
vous donnerait le résultat que vous attendez :
$ node test.js apples : oranges pears : prunes
Si vous souhaitez créer votre propre itérable, cela coûtera plus temps. Vous vous souvenez de ce qui a été dit plus tôt :
Un objet itérable est un objet qui définit la méthode @@ iterator, et la méthode @@iterator renvoie une implémentation de Un objet du protocole itérateur, ou la méthode est une fonction génératrice.
Le moyen le plus simple de comprendre ce contenu est de créer un objet itérable étape par étape. Tout d’abord, nous avons besoin d’un objet qui implémente la méthode @@iterator. La notation @@
est un peu trompeuse, ce que nous voulons vraiment faire, c'est définir la méthode en utilisant la notation Symbol.iterator
prédéfinie.
Si vous définissez un objet avec une méthode itératrice et essayez de parcourir :
const foo = { [Symbol.iterator]: function() { } } for(const [key, value] of foo) { console.log(key, value) }
vous obtenez une nouvelle erreur :
for(const [key, value] of foo) { ^ TypeError: Result of the Symbol.iterator method is not an object
C'est du javascript qui nous dit qu'il essaie pour appeler la méthode Symbol.iterator
, mais le résultat de l'appel n'est pas un objet .
Afin d'éliminer cette erreur, il est nécessaire d'utiliser la méthode iterator pour renvoyer un objet qui implémente le Protocole Iterator. Cela signifie que la méthode itératrice doit renvoyer un objet avec une clé next
, qui est une fonction. next
const foo = { [Symbol.iterator]: function() { return { next: function() { } } } } for(const [key, value] of foo) { console.log(key, value) }
for(const [key, value] of foo) { ^ TypeError: Iterator result undefined is not an object
, et l'objet Symbol.iterator
est bien un objet et implémente la méthode , mais la valeur de retour de next
n'est pas un objet javascript attendu. next
next
函数需要返回有特定格式的对象——有 value
和 done
这两个键。
next: function() { //... return { done: false, value: 'next value' } }
done
键是可选的。如果值为 true
(表示迭代器已完成迭代),则说明迭代已结束。
如果 done
为 false
或不存在,则需要 value
键。 value
键是通过循环此应该返回的值。
所以在代码中放入另一个程序,它带有一个简单的迭代器,该迭代器返回前十个偶数。
class First20Evens { constructor() { this.currentValue = 0 } [Symbol.iterator]() { return { next: (function() { this.currentValue+=2 if(this.currentValue > 20) { return {done:true} } return { value:this.currentValue } }).bind(this) } } } const foo = new First20Evens; for(const value of foo) { console.log(value) }
手动去构建实现迭代器协议的对象不是唯一的选择。生成器对象(由生成器函数返回)也实现了迭代器协议。上面的例子用生成器构建的话看起来像这样:
class First20Evens { constructor() { this.currentValue = 0 } [Symbol.iterator]() { return function*() { for(let i=1;i<=10;i++) { if(i % 2 === 0) { yield i } } }() } } const foo = new First20Evens; for(const item of foo) { console.log(item) }
本文不会过多地介绍生成器,如果你需要入门的话可以看这篇文章。今天的重要收获是,我们可以使自己的 Symbol.iterator
方法返回一个生成器对象,并且该生成器对象能够在 for ... of
循环中“正常工作”。 “正常工作”是指循环能够持续的在生成器上调用 next
,直到生成器停止 yield
值为止。
$ node sample-program.js 2 4 6 8 10
英文原文地址:https://alanstorm.com/es6s-many-for-loops-and-iterable-objects/
作者:Alan Storm
更多编程相关知识,请访问:编程视频!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!