From 39f2114f9797eb51994966c6bb8ff1814c9a4da8 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:36:08 +0100 Subject: unslug fr: move --- .../reference/iteration_protocols/index.html | 353 +++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 files/fr/web/javascript/reference/iteration_protocols/index.html (limited to 'files/fr/web/javascript/reference/iteration_protocols') diff --git a/files/fr/web/javascript/reference/iteration_protocols/index.html b/files/fr/web/javascript/reference/iteration_protocols/index.html new file mode 100644 index 0000000000..26a89a63e8 --- /dev/null +++ b/files/fr/web/javascript/reference/iteration_protocols/index.html @@ -0,0 +1,353 @@ +--- +title: Les protocoles d'itération +slug: Web/JavaScript/Reference/Les_protocoles_iteration +tags: + - ECMAScript 2015 + - Intermédiaire + - Iterator + - JavaScript + - Reference +translation_of: Web/JavaScript/Reference/Iteration_protocols +--- +
{{jsSidebar("More")}}
+ +

Un des ajouts à ECMAScript 2015 (ES6) n'est ni une nouvelle syntaxe ni un nouvel objet natif mais des protocoles. Ces protocoles peuvent être implémentés par n'importe quel objet qui respecte certaines conventions.

+ +

Il existe deux protocoles concernant l'itération : le protocole « itérable » et le protocole « itérateur ».

+ +

Le protocole « itérable »

+ +

Le protocole « itérable » permet aux objets JavaScript de définir ou de personnaliser leur comportement lors d'une itération, par exemple la façon dont les valeurs seront parcourues avec une boucle {{jsxref("Instructions/for...of", "for..of")}}. Certains types natifs tels que {{jsxref("Array")}} ou {{jsxref("Map")}} possèdent un comportement itératif par défaut, d'autres types, comme {{jsxref("Object")}} n'ont pas ce type de comportement.

+ +

Afin d'être itérable, un objet doit implémenter la méthode @@iterator, cela signifie que l'objet (ou un des objets de sa chaîne de prototypes) doit avoir une propriété avec une clé @@iterator qui est accessible via {{jsxref("Symbol.iterator")}} :

+ + + + + + + + + + + + + + +
PropriétéValeur
[Symbol.iterator]Une fonction sans argument qui renvoie un objet conforme au protocole itérateur.
+ +

Lorsqu'on doit itérer sur un objet (ex. : au début d'une boucle for..of), sa méthode @@iterator est appelée sans argument et l'itérateur qui est renvoyé est utilisé afin d'obtenir les valeurs sur lesquelles itérer.

+ +

Le protocole « itérateur »

+ +

Le protocole « itérateur » définit une façon standard pour produire une suite de valeurs (finie ou infinie) ainsi qu'une valeur de retour lorsque toutes les valeurs ont été générées.

+ +

Un objet est considéré comme un itérateur lorsqu'il implémente une méthode next() avec la sémantique suivante :

+ + + + + + + + + + + + +
PropriétéValeur
next +

Une fonction sans argument qui renvoie un objet qui possède au moins deux propriétés :

+ +
    +
  • done (un booléen) + +
      +
    • Qui vaut true lorsque l'itérateur a fini la suite. Dans ce cas, la propriété value sera facultative et permettra de spécifier la valeur de retour de l'itérateur. Les valeurs de retour sont détaillées ici.
    • +
    • Qui vaut false lorsque l'itérateur a pu produire la prochaine valeur de la suite. Si on ne définit pas la propriété done, on aura ce comportement par défaut.
    • +
    +
  • +
  • value : n'importe quelle valeur JavaScript, renvoyée par l'itérateur. Cette propriété peut être absente lorsque done vaut true.
  • +
+ +

La méthode next doit toujours renvoyer un objet contenant les propriétés done et value. Si c'est une valeur primitive qui est renvoyée (ex. false ou undefined), une exception {{jsxref("TypeError")}} sera levée ("iterator.next() returned a non-object value").

+
+ +

Certains itérateurs sont des itérables :

+ +
var unTableau = [1, 5, 7];
+var élémentsDuTableau = unTableau.entries();
+
+élémentsDuTableau.toString();    // "[object Array Iterator]"
+élémentsDuTableau === élémentsDuTableau[Symbol.iterator]();    // true
+
+ +

Exemples d'utilisation des protocoles d'itération

+ +

Une {{jsxref("String")}} est un exemple d'objet natif itérable :

+ +
var uneChaîne = "coucou";
+typeof uneChaîne[Symbol.iterator];           // "function"
+
+ +

L'itérateur par défaut d'un objet String renverra les caractères de la chaîne les uns à la suite des autres :

+ +
var itérateur = uneChaîne[Symbol.iterator]();
+itérateur + "";     // "[object String Iterator]"
+
+itérateur.next();  // { value: "c", done: false }
+itérateur.next();  // { value: "o", done: false }
+itérateur.next();  // { value: "u", done: false }
+itérateur.next();  // { value: "c", done: false }
+itérateur.next();  // { value: "o", done: false }
+itérateur.next();  // { value: "u", done: false }
+itérateur.next();  // { value: undefined, done: true }
+ +

Certains éléments natifs du langage, tels que la syntaxe de décomposition, utilisent ce même protocole :

+ +
[...uneChaîne];   // ["c", "o", "u", "c", "o", "u"]
+ +

Il est possible de redéfinir le comportement par défaut en définissant soi-même le symbole @@iterator :

+ +
var uneChaîne = new String("yo");          // on construit un objet String explicitement afin d'éviter la conversion automatique
+
+uneChaîne[Symbol.iterator] = function() {
+  return { // l'objet itérateur qui renvoie un seul élément, la chaîne "bop"
+    next: function() {
+      if (this._first) {
+        this._first = false;
+        return { value: "bop", done: false };
+      } else {
+        return { done: true };
+      }
+    },
+    _first: true
+  };
+};
+
+ +

On notera que redéfinir le symbole @@iterator affecte également le comportement des éléments du langage qui utilisent le protocole :

+ +
[...uneChaîne];  // ["bop"]
+uneChaîne + "";  // "yo"
+
+ +

Exemples d'itérables

+ +

Les itérables natifs

+ +

{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} et {{jsxref("Set")}} sont des itérables natifs car leurs prototypes possèdent une méthode @@iterator.

+ +

Les itérables définis par l'utilisateur

+ +

Il est possible de construire un itérable dans un script de la façon suivante :

+ +
var monItérable = {};
+monItérable[Symbol.iterator] = function* () {
+    yield 1;
+    yield 2;
+    yield 3;
+};
+[...monItérable]; // [1, 2, 3]
+
+ +

Les API natives utilisant des itérables

+ +

Plusieurs API utilisent les itérables, par exemple : {{jsxref("Map", "Map([itérable])")}}, {{jsxref("WeakMap", "WeakMap([itérable])")}}, {{jsxref("Set", "Set([itérable])")}} et {{jsxref("WeakSet", "WeakSet([itérable])")}} :

+ +
var monObjet = {};
+new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2);  // "b"
+new WeakMap([[{},"a"],[monObjet,"b"],[{},"c"]]).get(monObjet); // "b"
+new Set([1, 2, 3]).has(3);    // true
+new Set("123").has("2");      // true
+new WeakSet(function*() {
+    yield {};
+    yield monObjet;
+    yield {};
+}()).has(monObjet);           // true
+
+ +

ainsi que {{jsxref("Promise.all", "Promise.all(itérable)")}}, {{jsxref("Promise.race", "Promise.race(itérable)")}}, {{jsxref("Array.from", "Array.from()")}}

+ +

Les éléments de syntaxe utilisant des itérables

+ +

Certains éléments du langage utilisent des itérables, par exemple : for..of, la syntaxe de décomposition, yield*, l'affectation par décomposition :

+ +
for(let value of ["a", "b", "c"]){
+    console.log(value);
+}
+// "a"
+// "b"
+// "c"
+
+[..."abc"]; // ["a", "b", "c"]
+
+function* gen(){
+  yield* ["a", "b", "c"];
+}
+
+gen().next(); // { value:"a", done:false }
+
+[a, b, c] = new Set(["a", "b", "c"]);
+a; // "a"
+
+
+ +

Itérables mal-formés

+ +

Si une méthode @@iterator d'un objet itérable ne renvoie pas d'objet itérateur, on dira que cet objet est un itérable mal-formé. Utiliser de tels itérables peut provoquer des exceptions lors de l'exécution ou un comportement erratique :

+ +
var itérableMalFormé = {}
+itérableMalFormé[Symbol.iterator] = () => 1
+[...itérableMalFormé] // TypeError: [] is not a function
+
+ +

Exemples d'itérateurs

+ +

Un itérateur simple

+ +
function créerItérateur(tableau){
+    var nextIndex = 0;
+
+    return {
+       next: function(){
+           return nextIndex < tableau.length ?
+               {value: tableau[nextIndex++], done: false} :
+               {done: true};
+       }
+    }
+}
+
+var it = créerItérateur(['yo', 'ya']);
+
+console.log(it.next().value); // 'yo'
+console.log(it.next().value); // 'ya'
+console.log(it.next().done);  // true
+
+ +

Un itérateur infini

+ +
function créateurID(){
+    var index = 0;
+
+    return {
+       next: function(){
+           return {value: index++, done: false};
+       }
+    };
+}
+
+var it = créateurID();
+
+console.log(it.next().value); // '0'
+console.log(it.next().value); // '1'
+console.log(it.next().value); // '2'
+// ...
+
+ +

Avec un générateur

+ +
function* créerUnGénérateurSimple(tableau){
+    var nextIndex = 0;
+
+    while(nextIndex < tableau.length){
+        yield tableau[nextIndex++];
+    }
+}
+
+var gen = créerUnGénérateurSimple(['yo', 'ya']);
+
+console.log(gen.next().value); // 'yo'
+console.log(gen.next().value); // 'ya'
+console.log(gen.next().done);  // true
+
+function* créateurID(){
+    var index = 0;
+    while(true)
+        yield index++;
+}
+
+var gen = créateurID();
+
+console.log(gen.next().value); // '0'
+console.log(gen.next().value); // '1'
+console.log(gen.next().value); // '2'
+
+ +

Avec une classe ECMAScript 2015 (ES6)

+ +
class ClasseSimple {
+  constructor(data) {
+    this.index = 0;
+    this.data = data;
+  }
+
+  [Symbol.iterator]() {
+    return {
+      next: () => {
+        if (this.index < this.data.length) {
+          return {value: this.data[this.index++], done: false};
+        } else {
+          this.index = 0;
+          // En réinitialisant l'index, on peut
+          // "reprendre" l'itérateure sans avoir
+          // à gérer de mise à jour manuelle
+          return {done: true};
+        }
+      }
+    };
+  }
+}
+
+const simple = new ClasseSimple([1,2,3,4,5]);
+
+for (const val of simple) {
+  console.log(val);  // '1' '2' '3' '4' '5'
+}
+
+ +

Un générateur est-il un itérateur ou un itérable ?

+ +

Les deux réponses sont correctes :

+ +
var unObjetGénérateur = function*(){
+    yield 1;
+    yield 2;
+    yield 3;
+}()
+typeof unObjetGénérateur.next
+// "function", car il possède une fonction next, c'est donc un itérateur
+typeof unObjetGénérateur[Symbol.iterator]
+// "function", car il possède une méthode @@iterator, c'est donc un itérable
+unObjetGénérateur[Symbol.iterator]() === unObjetGénérateur
+// vrai car la méthode @@iterator renvoie elle-même, un itérateur, c'est donc un itérable bien formé
+[...unObjetGénérateur]
+// [1, 2, 3]
+
+ +

Spécifications

+ + + + + + + + + + + + + + + + + + + +
SpécificationÉtatCommentaires
{{SpecName('ES2015', '#sec-iteration', 'Iteration')}}{{Spec2('ES2015')}}Définition initiale
{{SpecName('ESDraft', '#sec-iteration', 'Iteration')}}{{Spec2('ESDraft')}} 
+ +

Voir aussi

+ + -- cgit v1.2.3-54-g00ecf