1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
---
title: Compréhensions de générateur
slug: Web/JavaScript/Reference/Opérateurs/Compréhensions_de_générateur
tags:
- Iterator
- JavaScript
- Non-standard
- Obsolete
- Reference
translation_of: Archive/Web/JavaScript/Generator_comprehensions
---
<div>{{JSSidebar("Operators")}}{{Non-standard_Header}}{{Obsolete_Header("gecko58")}}</div>
<div class="warning"><strong>Non-standard. Ne pas utiliser !</strong><br>
La syntaxe de compréhensions de générateurs ne sont pas une fonctionnalité standard et ont été retirées à partir de Firefox 58. Mieux vaut utiliser les {{jsxref("Instructions/function*", "générateurs", "", 1)}} pour des fonctionnalités similaires.</div>
<p>La syntaxe de <strong>compréhension de générateur</strong> était une expression qui permettait de construire rapidement une fonction génératrice à partir d'un objet itérable. Toutefois, cette syntaxe a été retirée du standard et de l'implémentation qui en est faite par Firefox. Elle ne doit pas être utilisée.</p>
<h2 id="Syntaxe">Syntaxe</h2>
<pre class="syntaxbox">(for (x of itérable) x)
(for (x of itérable) if (condition) x)
(for (x of itérable) for (y of itérable) x + y)
</pre>
<h2 id="Description">Description</h2>
<p>Une compréhension de générateur peut contenir deux sortes de composants :</p>
<ul>
<li>{{jsxref("Instructions/for...of", "for...of")}} et</li>
<li>{{jsxref("Instructions/if...else", "if")}}</li>
</ul>
<p>L'itération <code>for-of</code> est toujours le premier composant. Il est possible d'utiliser plusieurs itérations <code>for-of</code> et plusieurs instructions <code>if</code>.</p>
<p>Les {{jsxref("Opérateurs/Compréhensions_de_tableau","compréhensions de tableaux","","true")}} ont un inconvénient majeur : quand on les utilise, un nouveau tableau est créé en mémoire. Cela ne pose pas de problème particulier quand le tableau en question est petit (l'impact sera alors léger) mais lorsque le tableau est très grand (voire infini avec un générateur), cela peut poser problème que de vouloir créer un nouveau tableau.</p>
<p>Les générateurs permettent de calculer des suites à la demande (chaque élément successif est calculé lorsqu'on en a besoin). Les compréhensions de générateurs sont presque identiques, d'une point de vue syntaxique, aux compréhensions de tableaux. Plutôt d'utiliser des crochets, elles utilisent des parenthèses et au lieu de créer un tableau, elles créent un générateur qui pourra être utilisé. Cette notation peut être vue comme une notation raccourcie pour créer des générateurs.</p>
<p>Imaginons qu'on ait un itérateur qui parcourt une grande série d'entiers et qu'on veuille créer un itérateur qui itère sur les doubles de ces entiers. Une compréhension de tableau entraînerait la création d'un tableau complet en mémoire, dont les éléments seraient les valeurs doublées :</p>
<pre class="brush: js">var doubles = [for (i in it) i * 2];
</pre>
<p>En revanche, une compréhension de générateur permettrait de créer un nouvel itérateur qui pourrait être utilisé pour créer les valeurs doublées à la demande, quand on a besoin de les utiliser :</p>
<pre class="brush: js">var it2 = (for (i in it) i * 2);
console.log(it2.next()); // La première valeur, doublée
console.log(it2.next()); // La deuxième valeur, doublée
</pre>
<p>Lorsqu'une compréhension de générateur est utilisée comme un argument d'une fonction, les parenthèses utilisées pour l'appel de la fonction permettent de ne pas écrire les parenthèse encadrant la compréhension :</p>
<pre class="brush: js">var résultat = faireQuelqueChose(for (i in it) i * 2);
</pre>
<p>Avec la compréhension de générateur, on ne parcourt qu'une fois la structure de l'objet alors qu'avec une compréhension de tableau, on parcourt une fois le tableau pour construire la nouvelle version puis une seconde fois quand on souhaite l'utiliser.</p>
<h2 id="Exemples">Exemples</h2>
<h3 id="Compréhensions_simples">Compréhensions simples</h3>
<pre class="brush:js">(for (i of [ 1, 2, 3 ]) i*i );
// fonction génératrice qui générera 1, 4, et 9
[...(for (i of [ 1, 2, 3 ]) i*i )];
// [1, 4, 9]
var abc = [ "A", "B", "C" ];
(for (lettres of abc) lettres.toLowerCase());
// fonction génératrice qui générera "a", "b", et "c"
</pre>
<h3 id="Compréhensions_utilisant_une_instruction_if">Compréhensions utilisant une instruction <code>if</code></h3>
<pre class="brush: js">var années = [ 1954, 1974, 1990, 2006, 2010, 2014 ];
(for (année of années) if (année > 2000) année);
// fonction génératrice qui générera 2006, 2010, et 2014
(for (année of années) if (année > 2000) if(année < 2010) année);
// fonction génératrice qui générera 2006, équivaut à :
(for (année of années) if (année > 2000 && année < 2010) année);
// fonction génératrice qui générera 2006
</pre>
<h3 id="Compréhensions_de_générateurs_et_fonctions_génératrices">Compréhensions de générateurs et fonctions génératrices</h3>
<p>Pour mieux comprendre la syntaxe des compréhensions, on peut la comparer avec celle des fonctions génératrices :</p>
<p>Exemple 1 : Générateur simple.</p>
<pre class="brush: js">var nombres = [ 1, 2, 3 ];
// Fonction génératrice
(function*() {
for (let i of nombres) {
yield i * i;
}
})()
// Compréhension de générateur
(for (i of nombres) i*i );
// Résultat : les deux instructions renvoient chacune un générateur pour créer [ 1, 4, 9 ]
</pre>
<p>Second exemple : Un générateur avec <code>if</code>.</p>
<pre class="brush: js">var nombres = [ 1, 2, 3 ];
// Fonction génératrice
(function*() {
for (let i of nombres) {
if (i < 3) {
yield i * 1;
}
}
})()
// Compréhension
(for (i of nombres) if (i < 3) i);
// Résultat : les deux renvoient un générateur qui générera [ 1, 2 ]</pre>
<h2 id="Spécifications">Spécifications</h2>
<p>Était initialement prévu pour le brouillon ECMAScript 2015 mais fut retiré lors de la révision 27 (août 2014). Consulter les révisions antérieures d'ES2015 pour les spécifications de cette sémantique.</p>
<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2>
<div class="hidden">Ce tableau de compatibilité a été généré à partir de données structurées. Si vous souhaitez contribuer à ces données, n'hésitez pas à envoyer une <em>pull request</em> sur <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>.</div>
<p>{{Compat("javascript.operators.generator_comprehensions")}}</p>
<h2 id="Notes_relatives_à_l'implémentation_de_SpiderMonkey">Notes relatives à l'implémentation de SpiderMonkey</h2>
<ul>
<li>{{jsxref("Instructions/let", "let")}} n'est pas supporté comme identifiant car il n'est disponible qu'avec JavaScript 1.7 et pour la manipulations des balises de script XUL.</li>
<li>La décomposition, utilisée dans les compréhensions, n'est pas encore supportée ({{bug(980828)}}).</li>
</ul>
<h2 id="Différences_avec_les_anciennes_compréhensions_JS_1.7_et_JS_1.8">Différences avec les anciennes compréhensions JS 1.7 et JS 1.8</h2>
<div class="warning">
<p>Les compréhensions « JS1.7 / JS1.8 » ont été retirées à partir de Gecko 46 ({{bug(1220564)}}).</p>
</div>
<p><strong>Ancienne syntaxe pour les compréhensions (ne plus l'utiliser) :</strong></p>
<pre class="brush: js example-bad">[X for (Y in Z)]
[X for each (Y in Z)]
[X for (Y of Z)]
</pre>
<p>Les différences :</p>
<ul>
<li>Les compréhensions ES2016 créent une portée par nœud <code>for</code> et non pas une portée pour l'ensemble de la compréhension.
<ul>
<li>Ancienne version : <code>[...(()=>x for (x of [0, 1, 2]))][1]() // 2</code></li>
<li>Nouvelle version: <code>[...(for (x of [0, 1, 2]) ()=>x)][1]() // 1, chaque itération crée une nouvelle liaison pour x. </code></li>
</ul>
</li>
<li>Les compréhensions ES2016 débutent par <code>for</code> et non pas l'expression d'affectation.
<ul>
<li>Ancienne version : <code>(i * 2 for (i of nombres))</code></li>
<li>Nouvelle version : <code>(for (i of nombres) i * 2)</code></li>
</ul>
</li>
<li>Les compréhensions ES2016 peuvent utiliser plusieurs composants <code>if</code> et <code>for</code>.</li>
<li>Les compréhensions ES2016 ne fonctionnent qu'avec les boucles <code>{{jsxref("Instructions/for...of", "for...of")}}</code>, pas avec les boucles <code>{{jsxref("Instructions/for...in", "for...in")}}</code>.</li>
</ul>
<h2 id="Voir_aussi">Voir aussi</h2>
<ul>
<li>{{jsxref("Instructions/for...of", "for...of")}}</li>
<li>{{jsxref("Opérateurs/Compréhensions_de_tableau", "Compréhensions_de_tableau")}}</li>
</ul>
|