ITÉRATIONS, GÉNÉRATEUR, YIELD et NEXT E S 10 I t é r a t e u r s , G é n é r a t e u r s , & Itér ables J AVA S C R I P T (Programmation Internet) V O L . V I J.B. Dadet DIASOLUKA Luyalu Nzoyifuanga +243 - 851278216 - 899508675 - 991239212 - 902263541 - 813572818 CHAPITRE 10 : GÉNÉRATEUR, YIELD et NEXT : Les générateurs sont des fonctions qu'on peut quitter puis reprendre (continuer). Le contexte d'un générateur (les liaisons avec ses variables) est sauvegardé entre deux invocations. C’est donc aussi un bon moyen d’utiliser des variables statiques dans JavaScript, en plus des closures (fermetures, et curries [currying ou Curryfication]). Le corps d’une fonction génératrice function* (« generator », notez l’astérisque) n'est pas exécuté immédiatement lors de la création/définition d’une variable, mais plutôt renvoie un objet ayant seulement deux propriétés, la première ayant le nom « value » et qui emmagasine la valeur retournée par yield, la deuxième ayant le nom « done » qui indique si le générateur est toujours actif (pas terminé). La 1ère fois que la méthode « .next() » est appelé de l’objet itérateur créé, le corps de la fonction génératrice est exécuté de son début jusqu'à la première occurrence de l’instruction yield rencontrée, qui définira la valeur à renvoyer à l’objet itérateur qui l’aura appelé avec cette instruction « .next ». En fait tout se passe comme si (et c’est ainsi) « next » parcourt l’un après l’autre les éléments de l’itérable en incrémentant l’indexeur. J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Illustration et comparaison : I. VERSION STRING <script type = "text/javascript"> "use strict"; const s = "diasoluka"; // Chaîne let a = Array.from(s) , // Array i = 0; // index do { console.log(`s : ${a[i++]}`) } while (i < a.length); </script> <script type = "text/javascript"> "use strict"; console.log("=".repeat(15)); </script> II. VERSION PROTOCOLES D'ITÉRATION <script type = "text/javascript"> "use strict"; let alias; const si = "diasoluka"; // Chaîne var ii = si [Symbol.iterator](); // Équivaut à // let a = Array.from(s) , // Array // ii = 0; // index while(alias = ii.next() , ! alias.done){ console.log(`it = ${alias.value}`) }; // Cette boucle while() équivaut à // do { // console.log(`s : ${a[i++]}`) // } while (i < a.length); </script> N.B. : Un « objet itérateur » est créé sans l’opérateur « new ». Itérateur–Générateur–Itérables -3/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Tout comme la commande return, la commande yield renvoie une valeur de retour mais dans la propriété .value de l’objet itérateur. La commande return quant à elle renvoie la valeur de retour dans le propre type de cette dernière. Contrairement à return, yield ne clôt pas l’exécution de la fonction génératrice mais la suspend seulement pour être poursuivie à l’invocation de la prochaine méthode .next(), qui exécutera jusqu’à la rencontre de la prochaine instruction yield ou return. <script> function* repSces(obj) { console.log("Avant yield"); yield obj; } let it = repSces( console.log("Génération en cours")); console.log("Appel à .next()"); console.log(`it.next()= `, it.next()); </script> Itérateur–Générateur–Itérables -4/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI En simple, on peut dire que 1. yield est une sorte de return qui contrairement à ce dernier ne clôt pas mais suspend/interrompt l’exécution de la fonction génératrice. La valeur de la propriété « générateur.done » demeure true. 2. return retourne aussi une valeur mais clôt le générateur, la valeur de la propriété « générateur.done » devenant false. 3. Cette fonction génératrice est définie avec le mot clé iterator. 4. La méthode .next(), appelée pour la première fois, exécute toute la fonction génératrice jusqu’à yield. Les prochaines fois que .next() est appelée, elle poursuit l’exécution de la fonction génératrice là où yield l’avait suspendue. 5. Chaque appel à la méthode .next() doit avoir un yield qui lui est associé dans le générateur. Une façon facile de le garantir est d’utiliser une boucle valide qui contient l’instruction yield. Pendant qu’on est dans cette boucle yield renvoie une valeur valide, dès qu’on quitte la boucle elle (yield) renvoie undefined, à moins de prévoir des yield supplémentaire après et en dehors de cette boucle. 6. Mais il n’est pas nécessaire (bien que souvent inutile) d’avoir plus de yield dans le générateur que de .next() appelées. Itérateur–Générateur–Itérables -5/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI 7. Un yield n’est pas obligé d’être dans une boucle. 8. Tout comme return, yield renvoie des valeurs de tout type, pas seulement des booléennes, mais il (le yield) n’est pas non plus obligé d’en renvoyer explicitement, par exemple quand le .next() qui l’appelle utilise un ou des arguments. 9. La valeur de retour de yield peut être utilisée « in situ » [ex. console.log(yield)] ou être recueillie à partir de la propriété .« value » de la méthode .next() de l’obet générateur [ex. gen.next().value]. 10. Comme yield ne clôt pas la fonction mais seulement la suspend, les variables locales de la fonction génératrice persistent donc après cette suspension par yield. En fait on peut comprendre la méthode « next » comme demandant au « yield » d’envoyer la prochaine valeur de retour. 11. La boucle « for…of » agit sur les « itérables », tandis que la boucle « for…in » agit sur les « énumérables ». Mais « yield » permet aussi de créer un objet « itérable » : <script type="text/javascript"> "use strict"; const iterable = { *[Symbol.iterator]() { yield "Date() = " + Date(); yield "Date.now() = " + Date.now(); yield "Math.PI = " + Math.PI; yield "Math.E = " + Math.E; } }; for (let i of iterable) console.log(i); console.log([...iterable]) </script> Itérateur–Générateur–Itérables -6/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Une autre façon légèrement différente d’écrire le code ci-dessus : <script type="text/javascript"> "use strict"; const iterable = new Object(); iterable[Symbol.iterator] = function* () { yield "Date() = " + Date(); yield "Date.now() = " + Date.now(); yield "Math.PI = " + Math.PI; yield "Math.E = " + Math.E; }; for (let i of iterable) console.log(i); console.log([...iterable]) </script> Itérateur–Générateur–Itérables -7/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI <script> function* repSces(obj) { const couples = Object.getOwnPropertyNames(obj); // ou // const couples = Reflect.ownKeys(obj); for (const cle of couples) yield [cle, obj[cle]]; } // Les couples [cle,val] ds chaque objet-membre // de l'Array diags const diags = [ { nom: 'Likelele', sce: "Ophtalmo", path: "Cataracte" }, { nom: 'Monzele', sce: "Gynéco", path: "Leucorrhée" }, { nom: 'Ntaba', sce: "Vétérinaire", path: "Rage" } ]; let c=0; while(c < diags.length){ // Retourner un itérable pour chaque membre de diags. for (const [id,svce] of repSces(diags[c++])) { // Retourner [cle,val] pour chaque couple d'un // membre de diags. Itérateur–Générateur–Itérables -8/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(`${id}: ${svce}`); } console.log(`${"=".repeat(20)}`); } </script> Une extension de ce qui précède : I. Tous les traitements faits dans « *[Symbol.iterator]() {} » <script type="text/javascript"> "use strict"; let flagt=0, flagc=0, c=0, m = ["carie","parodontite","tartre","gingivite"]; const it = { *[Symbol.iterator]() { for(let k of m) { if(k=="tartre") flagt++; if(k=="crouzon") flagc++; yield ++c+". "+k; } } } Itérateur–Générateur–Itérables -9/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI for (let i of it) console.log(i); if(flagt)console.log("tartre était là"); if(flagc)console.log("Crouzon était là"); else console.log("Crouzon n'était pas là"); </script> II. Tous les traitements faits en dehors « *[Symbol.iterator]() {} », avec quelques modifications aussi : <script type="text/javascript"> "use strict"; let flagt=0, flagc=0, c=-2, m = ["carie","tartre","parodontite","gingivite"]; const it = { *[Symbol.iterator]() { for (let k of m) yield c+=2; } } for (let i of it){ if(m[i]=="tartre") flagt++; if(m[i]=="crouzon") flagc++; console.log(m[i]); } if(flagt)console.log("tartre était retenue"); else console.log("tartre n'était pas retenue"); if(flagc)console.log("Crouzon était là"); else console.log("Crouzon n'était pas là"); </script> Itérateur–Générateur–Itérables -10/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Un exemple pratique de la boucle itératrice « for…of » : Toutes les combinaisons 3 à trois des éléments de 3 Arrays de n’importe quelle taille : <script type="text/javascript"> "use strict"; const a1 = [3, 1, 6, 7], a2 = [8, 5, 0], a3 = [2, 4, 9, 5, 1]; let combo = [], t=""; for (let x of a1) for (let y of a2) for (let z of a3) combo.push([x , y , z]); let cptr=0; for (let v of combo) t += (++cptr).toString().padStart(2,'.') + ") " + v+' | '; console.log(t); </script> Itérateur–Générateur–Itérables -11/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Voici en clair comment s’est fait et comment doit se faire facilement l’indexation même manuellement : <script type="text/javascript"> "use strict"; const a1 = [0, 1, 2, 3], a2 = [0, 1, 2, 3], a3 = [0, 1, 2, 3]; let combo = [], t=""; for (let x of a1) for (let y of a2) for (let z of a3) combo.push([x , y , z]); let cptr=0; for (let v of combo) t += (++cptr).toString() .padStart(2,String .fromCharCode(183)) + ") " + v+' | '; console.log(t); </script> Et avec des lettres : <script type="text/javascript"> "use strict"; const a1 = ["L", "U", "Y"], Itérateur–Générateur–Itérables -12/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI a2 = ["L", "U", "Y"], a3 = ["L", "U", "Y"]; let combo = [], t=""; for (let x of a1) for (let y of a2) for (let z of a3) combo.push([x , y , z]); let cptr=0; for (let v of combo) t += (++cptr).toString() .padStart(2,String .fromCharCode(183)) + ") " + v+' | '; console.log(t); </script> Syntaxe de base d’une fonction génératrice : Déclaration de la fonction-génératrice : function* genFct(){ // Notez l’astérisque * var idx = 0; while (idx <= lim) // test de la condition yield idx++; // operation et ret value } Appel de la fonction itératrice : L’appel à une fonction génératrice ne l’exécute pas (n’exécute pas son Itérateur–Générateur–Itérables -13/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI corps), mais crée un objet « itérateur » qui permettra de contrôler ce corps de la fonction. Notez ici qu’on crée l’objet itérateur sans l’opérateur « new ». let it = genFct(); // Défnition de l’itérateur // = création de l'objet itérateur « it ». it.next(); it.next(); it.next(); it.next(); // // // // Appel Appel Appel Appel du du du du premier yield via « it » prochain yield " prochain yield " prochain yield " Exemple : <script type="text/javascript"> "use strict"; let cl = console.log; // Définition d'un générateur avec * function* fGenerator() { let current = 9; while (true) { // Boucle Indispensable yield current++; } yield; } // Fin Définition du générateur const it = fGenerator(); // Déf itérateur par appel au générateur cl(it.next().value); // 9 cl(it.next().value); // 10 cl(it.next().value.toString(2), " base 2"); // 1011 cl(it.next().value.toString(4), " base 4"); // 30 cl(it.next().value.toString(8), " base 8"); // 15 cl(it.next().value.toString(10), " base 10"); // 14 cl(it.next().value.toString(15), " base 15"); // 10 cl(it.next().value.toString(16), " base 16"); // 10 </script> Pour le cas ci-dessus, à la place de « while ( true ) » on peut utiliser Itérateur–Générateur–Itérables -14/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI « for ( ; ; ) » ou « do {...} while ( true ) », et à la place de true on peut utiliser n’importe quel test conditionnel valide : <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var index = 0; do{ yield index++; // prochaine instruction = do{}, tant que // la condition de la boucle est remplie. } while(index < 3) console.log("1er next Après la boucle") // Ne sera exécuté qu'une seule fois quand // la condition de la boucle n’est plus remplie, // avant le yield (return du generator) du // premier next quand on quitte la boucle. } // Fin function* numeroter() var it = numeroter(); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); </script> // // // // // // 0 1 2 1er next Après la boucle undefined undefined Une autre version de ça : <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var index = 0; do{ yield index++; } while(index < 12); console.log("1er next Après la boucle") } // Fin function* numeroter() const nc = [ "I = OLFACTIF, Se", "II = OPTIQUE, SDe", Itérateur–Générateur–Itérables -15/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI "III = OCULO-MOTEUR COMMUN (innerve tous les "+ "autres muscles extrinsèques, la musculature "+ "intrinsèque [muscle ciliaire {accommodation} "+ "et sphincter de l'iris], et le releveur de "+ "paupière supérieure), Mo", "IV = PATHÉTIQUE (=trochléaire. Innerve le "+ "grand oblique), Mo", "V = TRIJUMEAU, Mi", "VI = OCULO-MOTEUR EXTERNE (=abducens. "+ "Innerve le droit externe), Mo", "VII = FACIAL (Mi)", "VIII = VESTIBULO-COCHLÉAIRE, Se", "IX = GLOSSO-PHARYNGIEN, Mi", "X = PNEUMOGASTRIQUE (=Vague), Mi", "XI = SPINAL (=accessoire), Mi", "XII = GRAND HYPOGLOSSE, Mi." ]; var it = numeroter(); do{ var c = it.next().value; console.log(`* ${c+1}è paire => ${nc[c]}`); } while(nc[c]!=="XII = GRAND HYPOGLOSSE, Mi."); </script> Itérateur–Générateur–Itérables -16/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Et avec la boucle « for ... in » : <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var idx = [0,10,20,30]; for (let k in idx) {// prochaine instruction = for{ yield idx[k]; } // 0 10 20 30 undefined } var it = numeroter(); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); </script> // // // // // 0 10 20 30 undefined Quand on quitte la boucle de la fonction génératrice, celle-ci ne se clôt Itérateur–Générateur–Itérables -17/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI pas, mais le yield renvoie alors undefined. <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var idx = [0,20,10,30]; for (let k in idx) { yield idx[k]>15; } // false true false true undefined } var it = numeroter(); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); </script> // // // // // false true false true undefined . next() exécute toujours, et yield retourne une valeur de n’importe quel type, dans la propriété « value » de l’itérateur. <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var diag = { Conjonctivite:"sécrétions", Myopie:"lunettes", Rétinoblastome:"masse", Perforation:"herniation" }, // Object literal ([définition] littéral d’objet). ard=[ "Conjonctivite", "Myopie", "Rétinoblastome", "Perforation" ]; for (let idx=0;;idx++) { yield diag[ard[idx]]; Itérateur–Générateur–Itérables -18/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu } // sécrétions defi-ned } JavaScript Tome-VI lunettes masse herniation un- var it = numeroter(); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); </script> // // // // // // sécrétions lunettes masse herniation undefined undefined Une autre façon d’écrire ce même code : <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var index = 0; do{ yield index++; // prochaine instruction = do{}, tant que // la condition de la boucle est remplie. } while(index < 3) console.log("1er next Après la boucle") // 1er next Après la boucle // // Ne sera exécuté qu'une seule fois quand // la condition de la boucle n’est plus remplie, // avant le yield (return du generator) du // premier next quand on quitte la boucle. } // Fin function* numeroter() var it = numeroter(); const diag = { Conjonctivite:"sécrétions", Myopie:"lunettes", Rétinoblastome:"masse", Perforation:"herniation" }; Itérateur–Générateur–Itérables -19/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI let c; c = it.next().value; console.log(Object.entries(diag)[c][0], Object.entries(diag)[c][1]); // Conjonctivite sécrétions c = it.next().value; console.log(Object.entries(diag)[c][0], Object.entries(diag)[c][1]); // Myopie lunettes c = it.next().value; console.log(Object.entries(diag)[c][0], Object.entries(diag)[c][1]); // Rétinoblastome masse c = it.next().value; console.log(Object.entries(diag)[c][0], Object.entries(diag)[c][1]); // TypeError: // Object.entries(...)[c] is undefined; // can't access element at index 0 </script> La méthode .next() du générateur : La méthode .next() renvoie un objet dont : 1. La propriété value contient la valeur générée (par yield) et peut être manipulée librement. 2. Une propriété done qui indique si la boucle de la fonction génératrice est toujours active, donc si le générateur a ou pas produit sa dernière valeur soit-elle valide ou pas même quand la valeur retournée est undefined. AFFICHAGE DIRECT DE LA STRUCTURE INTERNE DE L’OBJET GÉNÉRATEUR : <script type="text/javascript"> "use strict"; function* Generator() { Itérateur–Générateur–Itérables -20/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI yield "Valeur retournée par yield"; } var gen = Generator(); var r; r=gen.next(); console.log(r); // Object { // value: "Valeur retournée par yield", // done: false // } // // // {…} // done: false // value: "Valeur retournée par yield" // <prototype>: Object { … } </script> AFFICHAGE VIA Object.getOwnPropertyDescriptors(yield retval) : <script type="text/javascript"> "use strict"; function* Generator() { yield "Valeur retournée par yield"; } var gen = Generator(); var r; r=gen.next(); console.log(Object.getOwnPropertyDescriptors(r)) // // // // // // // DANS CONSOLE DE FIREFOX 62.0.2 : Object { value: {…}, done: {…} } 1er niveau de détails (Firefox) : {…} Itérateur–Générateur–Itérables -21/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // done: Object { // value: false, // writable: true, // enumerable: true, … // } // value: Object { // value: "Valeur retournée par yield", // writable: true, // enumerable: true, … // } // <prototype>: Object { … } // // // 2e niveau de détails (Firefox) : // // done: {…} // configurable: true // enumerable: true // value: true // writable: true // <prototype>: Object { … } // value: {…} // configurable: true // enumerable: true // value: undefined // writable: true // <prototype>: Object { … } // <prototype>: Object { … } // // // // // // // // // // // // // // // // DANS CONSOLE DE YANDEX Version 18.10.1.385 beta {value: "Valeur retournée par yield", done: false} {value: {…}, done: {…}} 1er niveau de détails (Yandex) : done: { value: false, writable: true, enumerable: true, configurable: true } value: { Itérateur–Générateur–Itérables -22/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // value: "Valeur retournée par yield", // writable: true, // enumerable: true, // configurable: true // } // __proto__: Object // // // 2e niveau de détails (Yandex) : // // done: // configurable: true // enumerable: true // value: false // writable: true // __proto__: Object // value: // configurable: true // enumerable: true // value: "Valeur retournée par yield" // writable: true // __proto__: Object // __proto__: Object </script> AFFICHAGE VIA Object.getOwnPropertyNames(yield retval) : <script type="text/javascript"> "use strict"; function* Generator() { yield "Valeur retournée par yield"; } var gen = Generator(); var r; r=gen.next(); console.log(Object.getOwnPropertyNames(r)) // DANS CONSOLE DE FIREFOX 62.0.2 : // // Array [ "value", "done" ] // Itérateur–Générateur–Itérables -23/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // Un seul (1er) niveau de détails (Firefox) : // // (2) […] // 0: "value" // 1: "done" // length: 2 // <prototype>: Array [] // // // // // // // // // // // // // DANS CONSOLE DE YANDEX Version 18.10.1.385 beta (2) ["value", "done"] Un seul (1er) niveau de détails (Yandex) : (2) ["value", "done"] 0: "value" 1: "done" length: 2 __proto__: Array(0) </script> Les propriétés « value » et « done » de l’objet retourné par yield sont utilisées comme celles de tout autre objet (obj.prop). <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var diag = { Conjonctivite:"sécrétions", Myopie:"lunettes", Rétinoblastome:"masse", Perforation:"herniation" }, // Object literal ([définition] littéral d’objet). ard=[ "Conjonctivite", "Myopie", "Rétinoblastome", "Perforation" ]; Itérateur–Générateur–Itérables -24/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu for (let idx=0;;idx++) { yield diag[ard[idx]]; } // sécrétions lunettes ned } JavaScript Tome-VI masse herniation undefi- var gen = numeroter(); let r; r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value </script> + " " + r.done); // sécrétions false + " " + r.done); // lunettes false + " " + r.done); // masse false + " " + r.done); // herniation false + " " + r.done); // undefined false + " " + r.done); // undefined false La valeur generator.done du générateur devient true dès qu’on a fini avec le générateur : 1er exemple : <script type="text/javascript"> "use strict"; var r; function* idMaker() { var index = 2; while (Math.abs(index) < Math.abs(index+1)) yield index--; } var gen = idMaker(); r=gen.next(); console.log(r.value , r.done); // 2 r=gen.next(); console.log(r.value , r.done); // 1 r=gen.next(); console.log(r.value , r.done); // 0 Itérateur–Générateur–Itérables -25/54- false false false vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI r=gen.next(); console.log(r.value , r.done); // undefined true r=gen.next(); console.log(r.value , r.done); // undefined true r=gen.next(); console.log(r.value , r.done); // undefined true </script> 2e exemple : <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var index = 0; do{ yield index++; // prochaine instruction = do{}, tant que // la condition de la boucle est remplie. } while(index < 3) console.log("1er next Après la boucle") // Ne sera exécuté qu'une seule fois quand // la condition de la boucle n’est plus remplie, // avant le yield (return du generator) du // premier next quand on quitte la boucle. } // Fin function* numeroter() var gen = numeroter(); let r; r=gen.next(); console.log(r.value+" "+r.done); // r=gen.next(); console.log(r.value+" "+r.done); // r=gen.next(); console.log(r.value+" "+r.done); // r=gen.next(); console.log(r.value+" "+r.done); // 1er next Après la boucle // undefined r=gen.next(); console.log(r.value+" "+r.done); // r=gen.next(); console.log(r.value+" "+r.done); // Itérateur–Générateur–Itérables -26/54- 0 false 1 false 2 false undefined true undefined true vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // 0 false // 1 false // 2 false // 1er next Après la boucle // undefined true // undefined true // undefined true </script> test.html:21:1 test.html:23:1 test.html:25:1 test.html:10:3 test.html:27:1 test.html:29:1 test.html:31:1 Ci-dessous aussi, on quitte la boucle quand idx atteint ou dépasse 3 [ for (let idx=0;idx<3;idx++) ]. En ce moment-là aussi, generator.done est devenu true. <script type="text/javascript"> "use strict"; function* numeroter(){ // Constructeur var diag = { Conjonctivite:"sécrétions", Myopie:"lunettes", Rétinoblastome:"masse", Perforation:"herniation" }, // Object literal ([définition] littéral d’objet). ard=[ "Conjonctivite", "Myopie", "Rétinoblastome", "Perforation" ]; for (let idx=0;idx<3;idx++) { yield diag[ard[idx]]; } // sécrétions false, lunettes false, // undefined true, undefined true, masse false undefined true } var gen = numeroter(); let r; r=gen.next(); console.log(r.value + " " + r.done); // sécrétions false r=gen.next(); console.log(r.value + " " + r.done); // lunettes false Itérateur–Générateur–Itérables -27/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value r=gen.next(); console.log(r.value JavaScript Tome-VI + " " + r.done); // masse false + " " + r.done); // undefined true + " " + r.done); // undefined true + " " + r.done); // undefined true // sécrétions false // lunettes false // masse false // undefined true // undefined true // undefined true </script> test.html:28:1 test.html:30:1 test.html:32:1 test.html:34:1 test.html:36:1 test.html:38:1 Passation d’arguments à la fonction génératrice : On peut passer des arguments à la fonction génératrice lors de sa définition. Ces arguments se comportent dans la fonction génératrice exactement comme les paramètres des fonctions ordinaires. [En passant signalons que comme d’habitude, il est recommandé de ne jamais modifier la valeur de ces paramètres (mais on peut le faire si on veut) ; au besoin on ferait mieux d’affecter leurs valeurs à des variables locales]. <script type="text/javascript"> "use strict"; var v; function* generator(g,p) {// Constructeur console.log("Exécution du 1er yield") yield ; // retourne undefined console.log("Exécution du 2e yield") yield g; console.log("Exécution du 3e yield") yield g + v; console.log("Exécution du 4e yield") yield p + v; console.log("Exécution du 5e yield") yield g * p + v; Itérateur–Générateur–Itérables -28/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI } var gen = generator(5,10); console.log("Après définition du générateur"); v = 7; // Et/ou autres instructions... console.log(gen.next().value); // undefined v = 15; console.log(gen.next().value); // 5 v = 25; console.log(gen.next().value); // 30 v = 30; console.log(gen.next().value); // 40 v = 40; console.log(gen.next().value); // 90 console.log(gen.next().done) // true // RÉSULTATS // Après définition du générateur test.html:21:3 // Exécution du 1er yield test.html:4:6 // undefined test.html:24:3 // Exécution du 2e yield test.html:7:6 // 5 test.html:27:3 // Exécution du 3e yield test.html:10:6 // 30 test.html:30:3 // Exécution du 4e yield test.html:13:6 // 40 test.html:33:3 // Exécution du 5e yield test.html:16:6 // 90 test.html:36:3 // true test.html:38:3 </script> Itérateur–Générateur–Itérables -29/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI L’appel de la méthode .next() avec un argument reprendra l'exécution de la fonction génératrice, comme d’habitude là où elle s’était interrompue, et cet argument deviendra la valeur de retour de yield (remplacera la valeur de l'expression yield sans rien d’autre) mais à utiliser in situ (inline) : cet argument de .next() passé au générateur n’est pas retournée dans la propriété value de l’objet générateur. Vérifiez ci-dessous l’ordre d’exécution dans l’affichage de la console, et notez que l’argument du premier « appel au générateur avec argument » (« 1. Keliol ») n’a pas été utilisé (n’est pas affiché). <script type="text/javascript"> "use strict"; function* Generator() { console.log("0è instructions suite..."); yield "Depuis le générateur"; console.log("*** 1ère Série d'instructions..."); console.log(yield); console.log("*** 2ès instructions"); yield; console.log("*** 3ès instructions"); console.log(yield); console.log("*** 4ès instructions"); console.log(yield); console.log("*** 5ès instructions"); console.log(yield); console.log("*** 6ès instructions"); console.log(yield); } var gen = Generator(); // yield récupère automatiquement les arguments. console.log(gen.next().value); console.log(gen.next()('1. Keliol').value); console.log(gen.next()('2. Baron').value); console.log(gen.next()('3. Petrosa').value); Itérateur–Générateur–Itérables -30/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(gen.next()('4. Kelantina').value); </script> Exécution : 0è instructions suite... Depuis le généérateur *** 1ère Série d'instructions... undefined 2. Baron *** 2ès instructions undefined *** 3ès instructions undefined 4. Kelantina *** 4ès instructions undefined test.html:3:3 test.html:28:4 test.html:6:3 test.html:29:4 test.html:7:3 test.html:9:3 test.html:30:4 test.html:12:3 test.html:31:4 test.html:13:3 test.html:15:3 test.html:32:4 L’instruction return dans un générateur termine le générateur (done devenant true). La valeur renvoyée par return sera la valeur de terminaison du générateur. Une fois un générateur terminé, il ne peut plus produire d'autres valeurs. <script type="text/javascript"> "use strict"; var r; function* Generator() { console.log("*** 1ère Série d'instructions"); console.log("^^^^^^^",yield "Initio"); // Exécute d'abord yield (donc rentre vers le next appelant), // et donc interrompt et quitte le générateur sans le fermer, // et donc le console.log() ci-dessus // sera exécuté seulement au prochain .next(), mais // pas avec la valeur en cours de yield ("Initio"), mais // ave l'argument éventuel du .next() suivant ("2. Keliol..."). // Voir l'ordre d'exécution dans l'affichage de la console. Itérateur–Générateur–Itérables -31/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log("*** 2ès instructions"); console.log("^^^^^^^",yield); console.log("*** 3ès instructions"); return 45; // unreachable code after return statement test.html:10:5 console.log("*** 4ès instructions"); console.log(yield); console.log("*** 5ès instructions"); console.log(yield); console.log("*** 6ès instructions"); console.log(yield); } var gen = Generator(); r=gen.next(); console.log("=>",r,r.value,r.done," <="); // yield récupère automatiquement les arguments de .next(). r=gen.next()('2. Keliol [2è next]'); console.log(r,r.value,r.done); r=gen.next()('3. Baron [3è next]'); console.log(r,r.value,r.done); r=gen.next()('4. Petrosa [4è next]'); console.log(r,r.value,r.done); // value = 45 , done = true r=gen.next()('5. Kelantina [5è next]'); console.log(r,r.value,r.done); console.log("Les autres instructions exécutent..."); // *** 1ère Série d'instructions Itérateur–Générateur–Itérables -32/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // test.html:4:6 // => Object { value: "Initio", done: false } Initio false <= // test.html:38:4 // ^^^^^^^ 2. Keliol [2è next] // test.html:6:6 // *** 2ès instructions // test.html:16:6 // Object { value: undefined, done: false } undefined false // test.html:43:6 // ^^^^^^^ 3. Baron [3è next] // test.html:17:6 // *** 3ès instructions // test.html:19:6 // Object { value: 45, done: true } 45 true // test.html:46:10 // Object { value: undefined, done: true } undefined true // test.html:49:6 // Object { value: undefined, done: true } undefined true // test.html:53:6 // Les autres instructions exécutent... // test.html:55:4 // unreachable code after return statement [En savoir plus] // test.html:24:5 </script> Tentative de l’explication de l’Ordre d’exécution du code ci-dessus : 1. var gen = Generator(); Définition du générateur. 2. r=gen.next(); Demande d’exécuter le générateur jusqu’au premier yield y rencontré, ce qui poussera yield à renvoyer une valeur de retour à ce .next(), puis suspendre immédiatement l’exécution du générateur (pour notre cas ici même l’exécution du reste du console.log) et continuer l’exécution exactement à l’endroit où .next() l’a envoyée vers le générateur. L’exécution du programme s’y poursuivra jusqu’à rencontrer éventuellement le prochain .next() qui la redirigera de nouveau vers le générateur, exactement là où elle Itérateur–Générateur–Itérables -33/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI s’y est interrompue. Pour notre cas présent le programme reprendra l’exécution de « console.log ( " ^^^^^^^ " , yield " Initio " ) ; », c’est-à-dire d’abord la chaîne " ^^^^^^^ " puis la valeur proposée à yield, mais ce paramètre n’est plus le même et vaut maintenant la valeur de l’argument du .next() en cours (le deuxième .next()) et qui est : « '2 . Keliol [2è next ] ' » 3. Jusque-là le programme aura donc exécuté et affiché : console.log ( " *** 1ère Série d'instructions " ) ; => *** 1ère Série d'instructions test.html:4:6 et retourné un objet générateur avec « value="Initio" » à l’instruction console.log ( " => " , r , r . value , r . done , " <= " ) ; qui se trouve dans l’appelant et => Object { value: " Initio " , done: false } Initio false <= aura affiché : test.html:38:4 4. Le programme poursuivra son exécution normale dans l’appelant, jusqu’au prochain .next() (le deuxième) dans l'instruction cidessous : r = gen . next ( ' 2. Keliol [ 2è next ] ' ) ; À ce niveau-là le programme interrompra encore sa file dans l’appelant pour se rendre dans le générateur là où elle l’a quittée, pour y continuer son exécution, c’est-à-dira la suite de l’affichage de l’instruction « console . log ( yield ) ; » , avec les nouveaux paramètres de yield : « ‘2 . Keliol [ 2è next ] ' ». Itérateur–Générateur–Itérables -34/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Le programme y poursuivra l’exécution de la console qu’elle avait abandonnée, mais avec les paramètres en cours, ce qui affichera ^^^^^^^ 2. Keliol [2è next] test.html:6:6. 5. Le programme poursuit par la suite son exécution dans le générateur jusqu’au prochain yield ou return. Il croise dans l’entretemps l’instruction console . log ( " *** 2ès instructions " ) ; qu’il exécute en *** 2ès instructions affichant : test.html:16:6 Cette instruction étant une ordinaire, le programme se poursuit jusqu’au console.log(yield); Pendant l’exécution de cette dernière instruction (console.log(yield)), le programme exécutera naturellement d’abord l’argument de l’instruction c’est-à-dire le yield, qui retournera au générateur à l’objet générateur le paramètre du .next() qui a appelé son générateur, et qui devrait être affichée avec l’instruction ci-dessous : Console . log ( r , r . value , r . done ) ; pour afficher : Object { value : undefined , done : false } undefined false test.html:43:6 6. Le programme poursuit son exécution dans l’appelant jusqu’au prochain .next() (le troisième) : r = gen . next ( ' 3 . Baron [ 3è next ] ' ) ; Le programme rentre donc dans le générateur exactement là où il l’a Itérateur–Générateur–Itérables -35/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu quitté, JavaScript Tome-VI c’est-à-dire à l’instruction console . log ( " ^^^^^^^ " , yield ) ; Là, il continue l’affichage qu’il avait interrompu, comme expliqué plus haut, avec une nouvelle données pour yield (l’argument du .next() en cours), qui est : ' 3. Baron [ 3è next ] ' pour afficher : ^^^^^^^ 3. Baron [3è next] test.html:17:10 Il y continue jusqu’à rencontrer le prochain yield, c’est-à-dire exécute d’abord console . log ( " *** 3ès instructions " ) ; en affichant *** 3ès instructions test.html:19:6 puis continue jusqu’à rencontrer return qui clôt le générateur, tout en renvoyant la valeur arbitraire 45, comme ceci : return 45; 7. Le programme rentre donc dans l’appelant en renvoyant la valeur 45 à l’objet générateur dans l’appelant, pour y exécuter l’instruction console . log ( r , r . value , r . done ) ; qui affiche : Object { value: 45, done: true } 45 true test.html:46:6 Itérateur–Générateur–Itérables -36/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI indiquant aussi, avec la valeur,, que le générateur qui jusque-là était actif, est maintenant clos : gen . done == true . Yield avec astérisque (yield*) : Avec yield* (yield avec astérisque) la génération des valeurs est déléguée à une autre fonction génératrice. <script type="text/javascript"> "use var r; function* autreGen(i) { yield i * 2; // pour *B*, retourne yield i * 3; // pour *C*, retourne yield i * 4; // pour *D*, retourne } strict"; 30 = 15*2 45 = 15*3 60 = 15*4 var agen = autreGen(5); function* gen(i){ yield i; // Retourne 15 pour *A* seulement yield* autreGen(i); // délègue à yield* pour *B*, *C* et *D* // (puisque 3 yield ds autreGen), // avec i=15 (argument de yield*) console.log("agen*** ",agen.next().value); // agen*** 10 // 1er appel direct, donc 1er yiedl autreGen 10 = 5*2 yield i * 6; // Suite des yield dans gen, donc retourne 15*6 pour *E* yield i * 7; // Retourne 15*7=105 pour *F* } var gen = gen(15); // i ds gen = 15 Itérateur–Générateur–Itérables -37/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI r=gen.next(); console.log("A**gen ",r.value,r.done); // A**gen false 15 r=gen.next(); console.log("B**gen ",r.value,r.done); // B**gen false 30 r=gen.next(); console.log("C**gen ",r.value,r.done); // C**gen false 45 r=gen.next(); console.log("D**gen ",r.value,r.done); // D**gen false 60 r=gen.next(); console.log("E**gen ",r.value,r.done); // E**gen false 90 r=gen.next(); console.log("F**gen ",r.value,r.done); // F**gen false 105 r=gen.next(); console.log("F**gen ",r.value,r.done); // F**gen ned true // undefined : il n'y a plus de yield dans gen. </script> undefi- On ne peut pas utiliser l’opérateur « new » avec les générateurs. On dit qu’ils ne sont pas constructibles. <script type="text/javascript"> "use strict"; function* f() {} var obj = new f; // TypeError: f n'est pas un constructeur </script> Application : Génération aléatoire d’IMC en fonction de poids et tailles générés aléatoiItérateur–Générateur–Itérables -38/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI rement : <script type="text/javascript"> "use strict"; function* Generator() { let n=0; while(true){ var ech={ p : Math.round(Math.random()*60+20), t : Math.round(Math.random()*120+80) }, imc = ech["p"] * ech["p"] / ech["t"]; yield String(++n).padStart(2,'.')+ ". pds=" + String(ech["p"]).padStart(3,' ') + " kg , taille=" + String(ech["t"]).padStart(4,' ')+ " cm , imc=" + imc.toPrecision(4) + " kg²/cm" ; } } var gen = Generator(); for(let k=0 ; k<20 ; k++){ var r = gen.next(); console.log(r.value); } </script> Exéccution : .1. .2. .3. .4. .5. .6. .7. .8. .9. 10. 11. pds= pds= pds= pds= pds= pds= pds= pds= pds= pds= pds= 79 53 26 26 34 26 63 64 22 74 41 kg kg kg kg kg kg kg kg kg kg kg , , , , , , , , , , , taille= taille= taille= taille= taille= taille= taille= taille= taille= taille= taille= 198 127 89 95 184 180 153 109 124 88 182 Itérateur–Générateur–Itérables cm cm cm cm cm cm cm cm cm cm cm , , , , , , , , , , , imc=31.52 imc=22.12 imc=7.596 imc=7.116 imc=6.283 imc=3.756 imc=25.94 imc=37.58 imc=3.903 imc=62.23 imc=9.236 -39/54- kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu 12. 13. 14. 15. 16. 17. 18. 19. 20. pds= pds= pds= pds= pds= pds= pds= pds= pds= 28 34 46 58 36 77 43 51 29 kg kg kg kg kg kg kg kg kg , , , , , , , , , taille= taille= taille= taille= taille= taille= taille= taille= taille= 119 171 176 192 190 163 177 149 181 cm cm cm cm cm cm cm cm cm JavaScript Tome-VI , , , , , , , , , imc=6.588 imc=6.760 imc=12.02 imc=17.52 imc=6.821 imc=36.37 imc=10.45 imc=17.46 imc=4.646 kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm kg²/cm test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 test.html:23:7 Array de valeurs générées : <script type="text/javascript"> "use strict"; const obj = { *[Symbol.iterator]() { const max = 10; for (let i = 1; i <= max; i++) { yield i+". "+ Math.pow(2,i); } } }; for (let member of obj) { console.log(member); } </script> Exécution : 1. 2 2. 4 3. 8 4. 16 5. 32 6. 64 7. 128 8. 256 9. 512 10. 1024 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 test.html:12:3 En matière de table d’exposents de 2, voici comment on peut encore Itérateur–Générateur–Itérables -40/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI mieux le faire avec le CURRYING : https://gist.github.com/kavitshah8/d8ba19d09334d8e08a1f209fdbacb597 /raw/d96f9bab8f5fbbf5b4d9227f48c73a6848525524/curry2.js <script type="text/javascript"> "use strict"; function pow2x (a) { return Math.pow(2,a); } function compound (f) { return function (b) { return f(f(b)) } } for(let k=0;k<=10;k++){ console.log(2,"^",k,"=", pow2x(k) ) } console.log("") var p=1; for(let k=0;k<=10;k++){ var res=compound(pow2x)(k) console.log(p,"^",2,"=", compound(pow2x)(k) ) p=res } // // // // // // // // // // // 2 2 2 2 2 2 2 2 2 2 2 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 0 1 2 3 4 5 6 7 8 9 10 // 1 ^ 2 // 2 ^ 2 // 4 ^ 2 = = = = = = = = = = = = = 1 2 4 8 16 32 64 128 256 512 = 1024 2 4 16 Itérateur–Générateur–Itérables test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:12:23 test.html:18:3 test.html:18:3 test.html:18:3 -41/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // 16 ^ 2 = 256 test.html:18:3 // 256 ^ 2 = 65536 test.html:18:3 // 65536 ^ 2 = 4294967296 test.html:18:3 // 4294967296 ^ 2 = 18446744073709552000 // 18446744073709552000 ^ 2 = 3.402823669209385e+38 // 3.402823669209385e+38 ^ 2 = 1.157920892373162e+77 // 1.157920892373162e+77 ^ 2 = 1.3407807929942597e+154 // 1.3407807929942597e+154 ^ 2 = Infinity </script> Et <script type="text/javascript"> "use strict"; function pow2x (a) { return Math.pow(2,a); } function compound (f) { return function (b) { return function (c) { return Math.pow(f(f(b)),2) } } } for(let k=0;k<=10;k++){ console.log(2,"^",k," = ", pow2x(k) ) } console.log("") var p=1; for(let k=0;k<=10;k++){ var res=compound(pow2x)(k)(2) console.log(p,"^",2,"^",2,"=", compound(pow2x)(k)(2) ) p=Math.sqrt(res) } // // // // // // 2 2 2 2 2 2 ^ ^ ^ ^ ^ ^ 0 1 2 3 4 5 = = = = = = 1 2 4 8 16 32 Itérateur–Générateur–Itérables -42/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu // // // // // 2 2 2 2 2 ^ ^ ^ ^ ^ 6 7 8 9 10 = = = = JavaScript Tome-VI 64 128 256 512 = 1024 // 1 ^ 2 ^ 2 = 4 // 2 ^ 2 ^ 2 = 16 // 4 ^ 2 ^ 2 = 256 // 16 ^ 2 ^ 2 = 65536 // 256 ^ 2 ^ 2 = 4294967296 // 65536 ^ 2 ^ 2 = 18446744073709552000 // 4294967296 ^ 2 ^ 2 = 3.402823669209385e+38 // 18446744073709552000 ^ 2 ^ 2 = 1.157920892373162e+77 // 3.402823669209385e+38 ^ 2 ^ 2 = 1.3407807929942597e+154 // 1.157920892373162e+77 ^ 2 ^ 2 = Infinity // Infinity ^ 2 ^ 2 = Infinity </script> Itérateur–Générateur–Itérables -43/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI CHAPITRE 11 : ITÉRATIONS D'ÉNUMÉRABLES : Exemple d’itération : On peut créer un objet itérable en le définissant de type SET, dans une array, avec la commande var itObj = new Set() ; On crée alors son intance avec la commande var itInst = iterable[Symbol.iterator](); On parcourt les éléments de l’itérateur avec la méthode .next(), comme dans l’illustration ci-dessous : <script type="text/javascript"> "use strict"; const iterable = new Set([0,1,2,4,8,16,32,64,128,256,512,1024]); const it = iterable[Symbol.iterator](); let tot=""; while (true) { const res = it.next(); if (res.done) { break; } const item = res.value; tot += item + " = 2^" + Math.log2(item) + " | " } console.log(tot); </script> Exécution : Itérateur–Générateur–Itérables -44/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu 0 = 2^-Infinity 4 = 2^2 | 8 64 = 2^ 6 | 128 1024 = 2^10 | 2048 16384 = 2^14 | 32768 = = = = JavaScript Tome-VI | 1 = 2^0 | 2^ 3 | 16 = 2^ 7 | 256 = 2^11 | 4096 = 2^15 | 65536 = 2 = 2^ 1 | 2^ 4 | 32 = 2^ 5 | 2^ 8 | 512 = 2^ 9 | 2^12 | 8192 = 2^13 | 2^16 | Exemple d’itération avec le caractère singulier ( ` ) = ASCII 96 ou 60H ou <ALT-7> <ESPACE> en keybFr. utilisé pour délimiter l'argument à la méthode. Ce programme d’illustration est trop long, il sera découpé et abondamment commenté dans les prochaines éditions. <script type="text/javascript"> "use strict"; var obj = { obj:{} , L:"A" , 1:"Un", deux:2 , array:["texte",9,{o:"objet",s:6}] }; // ACCÈS DIRECT AUX PROPRIÉTÉS console.log( obj['obj'] , obj[1] , obj['array'] , obj['array'][2] ) // Object { } Un Array [ "texte", 9, {…} ] // Object { o: "objet", s: 6 } // ITÉRATIONS D'ÉNUMÉRABLES // // `objet.${prop} <*> ${obj[prop]}` // console.log("---","***","---"); for (const prop in obj) { console.log(`objet.${prop} <*> ${obj[prop]}`); // Notez le caractère singulier ( ` ) // = ASCII 96 ou 60H ou <ALT-7><ESPACE> en keybFr. // utilisé pour délimiter l'argument à la méthode // console.log() // « objet. » est un littéral arbitraire // ${prop} donne le nom (clé) de la propriété, Itérateur–Générateur–Itérables -45/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // ${obj[prop]} donne la valeur de la propriété. } // // // // // objet.1 <*> Un objet.obj <*> [object Object] objet.L <*> A objet.deux <*> 2 objet.array <*> texte,9,[object Object] // FOR (var prop IN obj) // object // console.log("---","***","---"); for (var prop in obj) { console.log(prop+" -> "+obj[prop]); } // 1 -> Un // obj -> [object Object] // L -> A // deux -> 2 // array -> texte,9,[object Object] // Object.entries(obj). FOREACH (([CLE,VAL]) // object // console.log("---","***","---"); Object.entries(obj).forEach(([cle,val])=>console.log(cle+" <-> "+val)); // 1 <-> Un // obj <-> [object Object] // L <-> A // deux <-> 2 // array <-> texte,9,[object Object] // Object.entries(obj) . FOREACH(([CLE]) // object // console.log("---","***","---"); Object.entries(obj).forEach(([cle]) => Itérateur–Générateur–Itérables -46/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(cle)); // // // // // 1 obj L deux array // Object.entries(obj) . FOREACH(([VAL]) // object // console.log("---","***","---"); Object.entries(obj).forEach(([,val]) => console.log(val)); // Un // Object { } // A // 2 // Array [ "texte", 9, {…} ] // FOR(var [cle,val] OF Object.entries(obj)) // object // console.log("---","***","---"); for(var [cle,val] of Object.entries(obj)) console.log("*"+cle+' ^ '+val); // *1 ^ Un // *obj ^ [object Object] // *L ^ A // *deux ^ 2 // *array ^ texte,9,[object Object] // Object.VALUES(obj) // object // console.log("---","***","---"); console.log(Object.values(obj)); // Array [ "Un", {}, "A", 2, […] ] // FOR (var idx IN obj.array) { // array Itérateur–Générateur–Itérables -47/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // console.log("---","***","---"); for (var idx in obj.array) { console.log(idx+" <-> "+obj.array[idx]); } // 0 <-> texte // 1 <-> 9 // 2 <-> [object Object] // FOR (var idx=0 ; idx<L ; idx++) // array // console.log("---","***","---"); for (var idx=0,l=obj.array.length ; idx<l ; idx++) { console.log(idx+" <<-> "+obj.array[idx]); } // 0 <<-> texte // 1 <<-> 9 // 2 <<-> [object Object] // Object.ENTRIES(obj.array) . FOREACH(([idx]) // array // console.log("---","***","---"); Object.entries(obj.array).forEach(([idx]) => console.log(idx+" -> "+obj.array[idx])); // 0 -> texte // 1 -> 9 // 2 -> [object Object] // FOR (var [idx] OF Object.entries(obj.array)) // array // console.log("---","***","---"); for(var [idx] of Object.entries(obj.array)) console.log("*"+idx+' ^ '+obj.array[idx]); // *0 ^ texte // *1 ^ 9 // *2 ^ [object Object] // Object.values(obj.array) Itérateur–Générateur–Itérables -48/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // array // console.log("---","***","---"); console.log(Object.values(obj.array)); // Array [ "texte", 9, {…} ] // FOR (var p IN obj.array[2]) // array // console.log("---","***","---"); for (var p in obj.array[2]) { console.log(p+" -> "+obj.array[2][p]); } // o -> objet // s -> 6 // // Les indexes dans une Array sont juste des // propriétés énumerables avec comme noms // des entiers, et sont identiques aux // propriétés d'un objet en général. // FOR (var i IN s) // String // console.log("---","***","---"); let s="Diasol"; for (var i in s) { console.log(i+" -> "+s[i]); } // 0 -> D // 1 -> i // 2 -> a // 3 -> s // 4 -> o // 5 -> l // APPLICATIONS PRATIQUES // HASOWNPROPERTY(prop) // console.log("---","***","---"); let triangle = {a: 1, b: 2, c: 3}; Itérateur–Générateur–Itérables -49/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI let epaisseur = {ep:"epais"}; function ColoredTriangle() { this.color = 'red'; } ColoredTriangle.aimepar = 15; // prop non héritable ColoredTriangle.prototype = triangle; // héritable (prot) ColoredTriangle.prototype = epaisseur; // héritable (prot) ColoredTriangle.prototype.pds = 120; // héritable (prot) var obj = new ColoredTriangle(); obj.brillant = true; console.log("ColoredTriangle.aimepar = "+ColoredTriangle.aimepar); // ColoredTriangle.aimepar = 15 console.log("obj.aimepar = "+obj.aimepar); // obj.aimepar = undefined console.log("===> ownProperties de l'INSTANCE"); // ===> ownProperties de l'INSTANCE console.log("---","***","---"); console.log(Object.getOwnPropertyNames(obj)); // Array [ "color", "brillant" ] for (const prop in obj) { console.log("> ",prop+ " <*> "+obj[prop]); // > color <*> red // > brillant <*> true // > ep <*> epais // > pds <*> 120 if (obj.hasOwnProperty(prop)) { console.log(`*** OWN PROP : obj.${prop} = ${obj[prop]}`); } // *** OWN PROP : obj.color = red // *** OWN PROP : obj.brillant = true } console.log("---","***","---"); Itérateur–Générateur–Itérables -50/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log("===> ownProperties du CONSTRUCTEUR"); // ===> ownProperties du CONSTRUCTEUR console.log(Object.getOwnPropertyNames(ColoredTriangle)); // Array [ "aimepar", "prototype", "length", "name" ] for (const prop in ColoredTriangle) { console.log("> ",prop+ " <*> "+ColoredTriangle[prop]); // > aimepar <*> 15 console.log("---","***","---"); if (ColoredTriangle.hasOwnProperty(prop)) { console.log(`*** OWN PROP : ColoredTriangle.${prop} = ${ColoredTriangle[prop]}`); } // *** OWN PROP : ColoredTriangle.aimepar = 15 } </script> Exécution : 4 -> o test.html:191:6 5 -> l test.html:191:6 --- *** --- test.html:205:3 ColoredTriangle.aimepar = 15 test.html:221:1 obj.aimepar = undefined test.html:224:1 ===> ownProperties de l'INSTANCE test.html:227:1 --- *** --- test.html:230:3 Array [ "color", "brillant" ] test.html:231:3 > color <*> red test.html:235:3 *** OWN PROP : obj.color = red test.html:242:5 > brillant <*> true test.html:235:3 *** OWN PROP : obj.brillant = true test.html:242:5 > ep <*> epais test.html:235:3 > pds <*> 120 test.html:235:3 --- *** --- test.html:248:1 ===> ownProperties du CONSTRUCTEUR test.html:250:1 Array(4) [ "aimepar", "prototype", "length", "name" ] test.html:253:1 > aimepar <*> 15 test.html:257:3 Itérateur–Générateur–Itérables -51/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI --- *** --- test.html:260:3 *** OWN PROP : ColoredTriangle.aimepar = 15 test.html:262:5 Kinshasa, le vendredi 31 mai 2019 - 11:27:03 PM Mots-clés : Variables statiques, Itération, énumérables, Set, function*, générateur, itérateur, fonction génératrice, iterator, yield, yield*, next, generator, constructibles, curry, currying, closures, fermetures, curries, curryfication, boucle, test conditionnel, javascript, opérateur new, ECMA, ECMASCRIPT, arguments, paramètres. Itérateur–Générateur–Itérables -52/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI DIASOLUKA Nz. Luyalu Docteur en Médecine, Chirurgie & Accouchements (1977), CNOM : 0866 - Spécialiste en ophtalmologie (1980) Études humanités : Scientifique - Mathématiques & Physique. Informaticien-amateur, Programmeur et WebMaster. Chercheur indépendant, autonome et autofinancé, bénévole, sans aucun conflit d’intérêt ou liens d'intérêts ou contrainte promotionnelle avec qui qu’il soit ou quelqu’organisme ou institution / organisation que ce soit, étatique, paraétatique ou privé, industriel ou commercial en relation avec le sujet présenté. +243 - 851278216 - 899508675 - 991239212 - 902263541 - 813572818 [email protected] Autre Lecture : https://www.scribd.com/document/374738470/Le-Plus-Grand-Secret-de-LaCreation D’autres publications pouvant aussi intéresser : • https://www.scribd.com/document/377036251/LeDosage-Des-Medicaments-en-Cac-Cas • https://www.scribd.com/document/377035454/LeItérateur–Générateur–Itérables -53/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Hasard-Des-Thermometres-Non-contact-a-Infrarouge • https://www.scribd.com/document/376222482/PetiteIntroduction-Aux-Fonctions-JavaScript • https://www.scribd.com/document/376221919/La-Foien-Jesus-Christ-Pour-Quoi-Faire • https://www.scribd.com/document/375689778/Lacuitevisuelle-angulaire • https://www.scribd.com/document/375349851/Lavariable-This • https://www.scribd.com/document/375024162/FonctionsImbriquees-en-JS • https://www.scribd.com/document/374789297/FormatInterne-Des-Objets-JavaScript • https://www.scribd.com/document/374788758/Iterationsen-JavaScript • https://www.scribd.com/document/374738470/Le-PlusGrand-Secret-de-La-Creation • https://www.scribd.com/document/374597969/NouvelleFormule-d-IMC-indice-de-doduite-Selon-Dr-Diasoluka • https://www.scribd.com/document/373847209/PropertyDescriptors • https://www.scribd.com/document/373833282/l-ObjetGlobal-Window • https://www.scribd.com/document/372665249/JavascriptTome-II • https://www.scribd.com/document/355291488/motiliteItérateur–Générateur–Itérables -54/54- vendredi, 31. mai 2019 (11:27 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI oculaire-2 • https://www.scribd.com/document/355291239/motiliteoculaire-I • https://www.scribd.com/document/355290248/Script-dAnalyses-Des-Reflexes-Pupillomoteurs • https://www.scribd.com/document/321168468/Renseigne ments-Id-et-Anthropometriques • https://www.scribd.com/document/320856721/Emission31-Jul-2016 • https://www.scribd.com/document/318182982/Complicati on-Visuelle-du-Traitement-de-La-Malaria • https://www.scribd.com/document/318180637/RapportEntre-Oxymetrie-Et-Type-Respiration • https://www.scribd.com/document/315746265/Classificati on-Des-Medicaments • https://www.scribd.com/document/315745909/Incongruen ces-Heresies-et-Heterodoxies-de-la-Notion-deLaboratoire • https://www.scribd.com/document/315745725/RapportEntre-Oxymetrie-Et-Type-Respiration Itérateur–Générateur–Itérables -55/54- vendredi, 31. mai 2019 (11:27 )