javascript tome vi - fonctions imbriquees en JS
Transcription
javascript tome vi - fonctions imbriquees en JS
fonctions imbriquées en javascript (nested function) J AVA S C R I P T (Programmation Internet) V O L . V I J.B. Dadet DIASOLUKA Luyalu Nzoyifuanga +243 - 851278216 - 899508675 - 995624714 - 902263541 - 813572818 La dernière révision de ce texte est disponible sur CD. CHAPITRE 12 : L e s f o n c t i o n s i m b r i q u é e s e n j a v a s c r i p t Contrairement aux langages C, en JavaScript les fonctions peuvent être imbriquées . Ceci parce qu’en JavaScript les fonctions sont des « objets de premier ordre » on dit aussi « objets de pre- mière classe » car elles peuvent être manipulées, échangées, avoir des propriétés et des méthodes, et surtout être passées en paramètre, comme tout autre objet JS. Une fonction JS, ordinaire soit-elle (càd sans propriétés ni méthodes propres), reste donc ni plus ni moins un objet Function (callable object), et inversement (tout objet est une fonction). Or justement les méthodes aussi sont ni plus ni moins des fonctions. Outre ses méthodes, une fonction peut posséder des fonctions ordinaires imbriquées [tout comme elle peut avoir des variables locales propres]. Mais une fonction imbriquée ne peut être appelée directement que du sein de la fonction qui l’englobe, jamais du dehors de cette fonction englobante. Ceci s’applique aussi aux J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI variables locales propres à la fonction. Donc fonctions imbriquées et variables propres d’une fonction ne sont pas directement accessible du dehors de la fonction englo- bante, sauf si on les retourne implicitement avec un « return ». Mais rappelez-vous que « return ») ne peut retourner qu’une et une seule valeur, et que pour retourner plusieurs valeurs [à une unique occasion] il faut les placer dans une structure telle que Array ou Objetde retour. <script type="text/javascript"> "use strict"; let fext = p => { let m=2; return _ => [m, Math.pow(m , p)]; } let exp = Math.round(Math.random()*10); let rtvf = fext(exp); // // // // Initialise à la valeur de la variable « exp » le paramètre p de la fonction englobante fext(); et récupération de l'adresse de la fonction retournée par englobante fext(). let retval = rtvf(); // // // // // // Appel de la fonction « ANONYME » retournée par la fonction englobante. Cette fonction imbriquée continuera à accéder aux paramètres et variables locales de la fonction qui l'englobe. La valeur (une ARRAY) retournée par la Fonctions Imbriquées - 2 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // fonction anonyme imbriquée est récupérée // par la variable « retval ». console.log( retval[0] + "^" + exp + " = " + retval[1] ); </script> Exécution: 2^10 = 1024 test.html:28:2 Les éléments renvoyés directement comme tels (pas leur pointeur) avec un « return » ne peuvent naturellement pas être modifiés dans leur milieu d’origine (l’intérieur de la fonction englobante) à partir de l’extérieur de la fonction englobante sauf si c’est un pointeur sur eux qui a été renvoyé (mais en JavaScript il n’existe pas de pointeur sur variable ordinaire). <script type="text/javascript"> "use strict"; let fext = p => { let m=2; return _ => [m, Math.pow(m , p)]; } let exp = Math.round(Math.random()*10); let rtvf = fext(exp); // // // // Initialise à la valeur de la variable « exp » le paramètre p de la fonction englobante fext(); et récupération de l'adresse de la fonction retournée par englobante fext(). Fonctions Imbriquées - 3 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI let retval = rtvf(); // // // // // // // // Appel de la fonction « ANONYME » retournée par la fonction englobante. Cette fonction imbriquée continuera à accéder aux paramètres et variables locales de la fonction qui l'englobe. La valeur (une ARRAY) retournée par la fonction anonyme imbriquée est récupérée par la variable « retval ». console.log( retval[0] + "^" + exp + " = " + retval[1] ); // Affichage de la valeur multiple retournée // par la fonction imbriquée. /////////////////////////////////////////////// // Tentative de Modification d'une fonction // // imbriquée en dehors de la fonction // // qui l'englobe. // /////////////////////////////////////////////// let fprot = _ => console.log("Success"); // Définition d'une nouvelle fonction (fléchée) retval.prototype = fprot; // On colle, de l'extérieur, un prototype à // la fonction imbriquée. retval.prototype(); Fonctions Imbriquées - 4 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // On appelle ce prototype bien sûr // toujours de l'extérieur. console.dir(rtvf); // Vérification de la configuration actuelle // de notre fonction imbriquée, via son // pointeur « rtvf ». // function fext() // fext() // length: 1 // name: "" // <prototype>: function () test.html:66:3 // Nous voyons bien ci-dessus que notre // pointeur « rtvf » représente bien (pointe sur) // notre fonction englobante externe « fext() ». console.dir(retval); // Vérification de la configuration actuelle // de notre fonction imbriquée, via son // pointeur « retval ». // Array [ 2, 16 ] test.html:86:3 // (2) […] // 0: 2 // 1: 16 // length: 2 // prototype: function fprot() // <prototype>: Array [] // // // // // Nous voyons bien que la valeur retournée par la fonction imbriquée et une ARRAY, donc une valeur multiple, et que le prototype de cette fonction a bel et bien été "sémaphoré" sur « frot() ». Fonctions Imbriquées - 5 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI </script> Rappelez-vous aussi que toute instruction qui vient après « return » dans un même bloc d’instruction est ignoré pour la simple et bonne raison que l’exécution ne se poursuit pas au-delà de return, à moins d’y aller grâce aux labels et une instruction « goto » en amont de « return ». Mais le « goto » est trop intrusif et comporte beaucoup d’autres inconvénients : http://www.acm.org/classics/oct95/ Bien entendu, il reste tout de même des situations où « goto » rest préférable, plus rapide et plus performant, mais il n’existe dans JavaScript que comme mot-clé mais n’y est pas utilisable. Le « label » en JavaScript n’étiquette pas n’importe quel endroit du code source, mais étiquette seulement [le début d’] une boucle qu’on peut quitter avec une « break » ou reboucler avec une « continue » qui se substituent à « goto ». Les deux versions d’un même code ci-dessous relatif à des boucles imbriquées (l’une sans l’instructio « goto » et l’autre avec l’instruction « goto » à laquelle on a substitué l’istruction « break ») font presque la même chose, mais dommage que ça Fonctions Imbriquées - 6 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI montre une certaine supériorité de « goto » dans certaines circonstances. <script type="text/javascript"> "use strict"; let tmp=null, cpt=null, faux=null; </script> <script type="text/javascript"> "use strict"; console.log("SANS « GOTO LABEL »"); const m1 = [7,3,15,20,1,5,9,15,6,35,27]; const e1 = [1,25,3,5,7,9,15,75]; console.log(m1,e1) console.log("") faux=cpt=0; tmp="" const d1=new Date(); for(let km=0,kml=m1.length ; km<kml ; km++){ for(let ke=0,kel=e1.length ; ke<kel ; ke++){ tmp+= ++cpt +" "; if(!(m1.includes(e1[ke]))) { // faux++; m1.push(e1[ke]); break; // ou faux++; m1.push(e1[ke]);ke=kel; } } // if(faux) break; // ou if(faux) km=kml; } if(faux) console.log(m1," .not.included ",e1) else console.log(m1," included ",e1) console.log("Durée = ",((new Date())-d1)/1000+" secs") console.log(tmp+" passes.") </script> <script type="text/javascript"> "use strict"; console.log(""); Fonctions Imbriquées - 7 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu </script> JavaScript Tome-VI <script type="text/javascript"> "use strict"; console.log("AVEC « GOTO LABEL »"); const m2 = [7,3,15,20,1,5,9,15,6,35,27]; const e2 = [1,25,3,5,7,9,15,75]; console.log(m2,e2) console.log("") faux=cpt=0; tmp="" const d2=new Date(); quitLab: for(let km=0,kml=m2.length ; km<kml ; km++){ forthLab: for(let ke=0,kel=e2.length ; ke<kel ; ke++){ tmp+= ++cpt +" "; if(!(m2.includes(e2[ke]))) { faux++; m2.push(e2[ke]); break quitLab; // Quitter la boucle qui suit quitLab. } else continue forthLab; } } if(faux) console.log(m2," .not.included ",e2) else console.log(m2," included ",e2) console.log("Durée = ",((new Date())-d2)/1000+" secs") console.log(tmp+" passes.") </script> Exécution : 1. Les deux versions sans « goto » et avec « goto » s’arrêtent dès qu’elles rencontrent le premier élément de l’array « e » Fonctions Imbriquées - 8 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI (d’échantillons) qui n’existe pas dans l’array « m » (modèle ou de référence) et qu’elles ajoutent cet élément de trop à l’array modèle, et s’arrêtent là. 2. La version sans « goto » a exécuté en 0.001 secs, alors que celle avec « goto » a exécuté en moins de temps (0.000 sec). 3. Les deux versions (sans et avec « goto ») ont exécuté avec le même nombre de passes = 2. 07:25:23,833 SANS « GOTO LABEL » test.html:7:3 07:25:23,837 Array(11) [ 7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27 ] Array(8) [ 1, 25, 3, 5, 7, 9, 15, 75 ] test.html:10:3 07:25:23,843 Array(12) [ 7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27, 25 ] .not.included Array(8) [ 1, 25, 3, 5, 7, 9, 15, 75 ] test.html:29:12 07:25:23,845 Durée = 0.003 secs 07:25:23,845 1 2 passes. test.html:31:3 test.html:32:3 07:25:23,847 AVEC « GOTO LABEL » test.html:46:3 07:25:23,848 Array(11) [ 7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27 ] Array(8) [ 1, 25, 3, 5, 7, 9, 15, 75 ] test.html:49:3 07:25:23,849 Fonctions Imbriquées - 9 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Array(12) [ 7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27, 25 ] .not.included Array(8) [ 1, 25, 3, 5, 7, 9, 15, 75 ] test.html:70:12 07:25:23,851 Durée = 0.001 secs test.html:72:3 07:25:23,851 1 2 passes. test.html:73:3 Ci-après, une versions qui parcourt tous les éléments de l’array « e » des échantillons pour les comparer tous aux éléments de l’array modèle « m », et ajoute à cette dernière tous les éléments qui sont de trop dans l’array d’échantillons. <script type="text/javascript"> "use strict"; let tmp=null, cpt=null, faux=null; </script> <script type="text/javascript"> "use strict"; console.log("SANS « GOTO LABEL »"); const m1 = [7,3,15,20,1,5,9,15,6,35,27]; const e1 = [1,25,3,85,7,9,15,75]; console.log(m1,e1) console.log("") faux=cpt=0; tmp="" const d1=new Date(); for(let km=0,kml=m1.length ; km<kml ; km++){ for(let ke=0,kel=e1.length ; ke<kel ; ke++){ tmp+= ++cpt +" "; if(!(m1.includes(e1[ke]))) { // faux++; m1.push(e1[ke]); break; // ou faux++; m1.push(e1[ke]); ///////////// ke=kel; } Fonctions Imbriquées - 10 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI } // if(faux) break; // ou ////////////////// if(faux) km=kml; } if(faux) console.log(m1," .not.included ",e1) else console.log(m1," included ",e1) console.log("Durée = ",((new Date())-d1)/1000+" secs") console.log(tmp+" passes.") </script> <script type="text/javascript"> "use strict"; console.log(""); </script> <script type="text/javascript"> "use strict"; console.log("AVEC « GOTO LABEL »"); const m2 = [7,3,15,20,1,5,9,15,6,35,27]; const e2 = [1,25,3,85,7,9,15,75]; console.log(m2,e2) console.log("") faux=cpt=0; tmp="" const d2=new Date(); quitLab: for(let km=0,kml=m2.length ; km<kml ; km++){ for(let ke=0,kel=e2.length ; ke<kel ; ke++){ tmp+= ++cpt +" "; if(!(m2.includes(e2[ke]))) { faux++; m2.push(e2[ke]); // break quitLab; // On ne quitte pas la boucle externe. } else continue; } } if(faux) console.log(m2," .not.included ",e2) else console.log(m2," included ",e2) Fonctions Imbriquées - 11 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log("Durée = ",((new Date())-d2)/1000+" secs") console.log(tmp+" passes.") </script> Exécution : 1. Les deux versions sans « goto » et avec « goto » ne s’arrêtent que quand ils ont fini de parcourir tous les éléments de l’array « e » (d’échantillons) en les comparant avec les éléments de l’array « m » (modèle ou de référence) et lui ajoutent tous les éléments qui sont de trop dans l’array « e ». 2. La version sans « goto » a exécuté en 0.003 secs, alors que celle avec « goto » a exécuté en moins de temps (0.002 sec). 3. Les deux versions (sans et avec « goto ») ont exécuté avec le même nombre de passes = 88. test.html:7 SANS « GOTO LABEL » test.html:10 (11) [7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27] (8) [1, 25, 3, 85, 7, 9, 15, 75] test.html:29 (14) [7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27, 25, 85, 75] " .not.included " (8) [1, 25, 3, 85, 7, 9, 15, 75] test.html:31 Durée = Fonctions Imbriquées 0.003 secs - 12 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI test.html:32 1 2 3 4 5 6 7 8 9 23 24 25 26 27 28 42 43 44 45 46 47 61 62 63 64 65 66 80 81 82 83 84 85 10 29 48 67 86 test.html:46 AVEC « GOTO LABEL » 11 30 49 68 87 12 31 50 69 88 13 14 15 32 33 34 51 52 53 70 71 72 passes. 16 35 54 73 17 36 55 74 18 37 56 75 19 38 57 76 20 39 58 77 21 40 59 78 22 41 60 79 test.html:49 (11) [7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27] (8) [1, 25, 3, 85, 7, 9, 15, 75] test.html:65 (14) [7, 3, 15, 20, 1, 5, 9, 15, 6, 35, 27, 25, 85, 75] " .not.included " (8) [1, 25, 3, 85, 7, 9, 15, 75] test.html:67 Durée = test.html:68 1 2 3 4 5 6 7 8 9 23 24 25 26 27 28 42 43 44 45 46 47 61 62 63 64 65 66 80 81 82 83 84 85 10 29 48 67 86 0.002 secs 11 30 49 68 87 12 31 50 69 88 13 14 15 32 33 34 51 52 53 70 71 72 passes. 16 35 54 73 17 36 55 74 18 37 56 75 19 38 57 76 20 39 58 77 21 40 59 78 22 41 60 79 Mais il serait plus intéressant que le label (ici « quitLab: ») puisse être placé APRÈS les deux boucles imbriquées ce qui serait plus pratique dans certains cas, mais ça semble impossible même quand on appelle la fonction (qui contient le label) « onload » : <script type="text/javascript"> "use strict"; const m2 = [7,3,15,20,1,5,9,15,6,35,27]; const e2 = [1,25,3,85,7,9,15,75]; console.log(m2,e2) console.log("") Fonctions Imbriquées - 13 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI var faux=0; </script> <script type="text/javascript"> "use strict"; quitLab: for(let km=0,kml=m2.length ; km<kml ; km++){ for(let ke=0,kel=e2.length ; ke<kel ; ke++){ if(!(m2.includes(e2[ke]))) { faux++; break quitLab; } else continue; } } </script> <script type="text/javascript"> "use strict"; function fLabel(){ for(let km=0,kml=m2.length ; km<kml ; km++){ for(let ke=0,kel=e2.length ; ke<kel ; ke++){ if(!(m2.includes(e2[ke]))) { faux++; // // // // // break quitLab2; Yandex Uncaught SyntaxError: Undefined label 'quitLab2' FireFox SyntaxError: label not found } else continue; } } quitLab2: console.log("Suite") } fLabel(); </script> Fonctions Imbriquées - 14 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Exécution : 06:31:40,315 Array(11) [ 7, 3, 15, 20, 1, 5, 9, 15, 6, 35, … ] Array(8) [ 1, 25, 3, 85, 7, 9, 15, 75 ] test.html:6:3 06:31:40,321 SyntaxError: label not found test.html:30:14 Revenons à nos chers moutons et illustrons la non accessibilité d’une fonction imbriquée depuis le dehors de la fonction qui l’englobe. EXEMPLE 1: Non accessibilité d’une fonction imbriquée du dehors de sa fonction englobante. <script type="text/javascript"> "use strict"; function personne(){ function congrats(){ console.log( "Hello"); // Hello test.html:4:13 } congrats(); return "Englobante"; } Fonctions Imbriquées - 15 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(personne()); // Englobante test.html:10:1 console.log(congrats()); // Uncaught ReferenceError: // congrats is not defined console.log(personne.congrats()); // Uncaught TypeError: // personne.congrats is not a function </script> On peut toutefois contourner certaines de ces limitations en faisant que la fonction englobante renvoie un pointeur sur (= adresse de) la fonction imbriquée, permettant de l’appeler de l’extérieur de la fonction englobante, l’adresse renvoyée pouvant éventuellement être stockée dans une variable. EXEMPLE 2: <script type="text/javascript"> function personne(p){ function congrats(c){ console.log(p,c); } "use strict"; console.log("Appel interne de congrats('Kibinda')") congrats("Kibinda"); // Bonjour Kibinda test.html:4:13 return congrats; } const r = personne("Bonjour"); Fonctions Imbriquées - 16 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log("Appel externe de r('Koye')") r("Koye"); // Bonjour Koye test.html:4:13 </script> Exécution : Appel interne de congrats('Kibinda') Bonjour Kibinda Appel externe de r('Koye') Bonjour Koye test.html:8:9 test.html:4:13 test.html:14:1 test.html:4:13 Les membres d’une fonction ont une portée/visibilité locale (limitée au bloc de cette fonction) : pas accessibles du dehors de la fonction. Vous pouvez normalement vous arranger pour éventuellement appeler la fonction imbriquée seulement du sein-même de la fonction englobante. Vous l’exécutez bien sûr, mais pas du dehors de la fonction englobante. <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || Fonctions Imbriquées - 17 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// recommendation(gender); ///////////////////////////////// } personne(1993,""); // NIHIL. personne(1953,""); // SEXE VIDE. test.html:22:11 personne(1953,"H"); // Attention! Âge 65 > 50 ans! // Veillez à L'ANDROPAUSE personne(1953,"F"); // Attention! Âge 65 > 50 ans! // Veillez à LA MÉNOPAUSE </script> test.html:15:11 test.html:19:11 Une façon de contourner cette restriction est de créer au sein de la fonction englobante un membre (propriété) portant le même nom que la fonction englobante, cette propriété servira de « clé » pour accéder à la fonction imbriquée, sans le mot-clé var, ni le Fonctions Imbriquées - 18 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI mot-clé this. <script language="JavaScript"> "use strict"; function personne(dn){ let age=(new Date()).getFullYear() - dn function recommandation(sx){ if(!sx) sx=""; if(age>50){ const msg="Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// personne.rec = recommandation; ///////////////////////////////// } personne(1953); personne.rec("Homme"); // Attention! Âge [65] > 50 ans! // Veillez à L'ANDROPAUSE </script> test.html:11:16 Une autre façon d’appeler la fonction imbriquée du dehors de la fonction englobante est de faire de la fonction imbriquée une méFonctions Imbriquées - 19 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI thode de la fonction englobante, avec le mot-clé this. On crée là un constructeur d’objet. Ensuite créer une instance de la fonction englobante, et appeler la fonction imbriquée comme méthode de l’instance. <script language="JavaScript"> "use strict"; function personne(dn){ let age=(new Date()).getFullYear() - dn // age === var locale, pas propriété /* // Vous pouvez accéder à une propriété en dehors du constructeur, du sein de ses instances. // Mais vous ne pouvez accéder à une variable locale que du sein de la fonction (ici le constructeur). */ this.recommandation = function(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } } const inst = new personne(1953); Fonctions Imbriquées - 20 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI inst.recommandation("Femme"); // Attention! Âge 65 > 50 ans! Veillez à LA MÉNOPAUSE </script> Au besoin, vous pouvez utiliser la technique de curry function, on parle alors de fermeture (= closure): <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// return recommendation; ///////////////////////////////// } let emissaire=personne(1953); var rec = emissaire("Homme") // Attention! Âge 65 > 50 ans! Veillez à L'ANDROPAUSE var rec = emissaire("Femme") Fonctions Imbriquées - 21 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI // Attention! Âge 65 > 50 ans! Veillez à LA MÉNOPAUSE var rec = emissaire("") // SEXE VIDE. </script> Vous pouvez aussi appeler la fonction englobante et la fonction imbriquée dans une même instruction, par une succession de parenthèses : <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; let L=50; const msg="Attention! Âge "+age+ ` ${age>=50?'>=':'<'} ` + L+" ans! Veillez à"; if(age>=(L=50)){ if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log(msg,"...Sexe Vide.".toUpperCase()) } } else console.log( msg,"...VoTrE jeUnesSe.".toUpperCase() ) } return recommendation; Fonctions Imbriquées - 22 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI } let emissaire; ///////////////////////////////// emissaire=personne(1963)("Homme") // Attention! Âge 55 >= 50 ans! Veillez à L'ANDROPAUSE emissaire=personne(1973)("Mâle") // Attention! Âge 45 < 50 ans! Veillez à ...VOTRE JEUNESSE. emissaire=personne(1953)("") // Attention! Âge 65 >= 50 ans! Veillez à ...SEXE VIDE. emissaire=personne(1919)("Femelle") // Attention! Âge 99 >= 50 ans! Veillez à LA MÉNOPAUSE emissaire=personne(1969)() // Attention! Âge 49 < 50 ans! Veillez à ...VOTRE JEUNESSE. emissaire=personne(1968 , "Femme")() // Attention! Âge 50 >= 50 ans! Veillez à ...SEXE VIDE. emissaire=personne()("Femme",1923) // Attention! Âge NaN < 50 ans! Veillez à ...VOTRE JEUNESSE. ///////////////////////////////// </script> Vous pouvez aussi faire en sorte de n’appeler la fonction « recommandation » que sous certaines conditions selon le statu renvoyé par la fonction englobante. <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn Fonctions Imbriquées - 23 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// return [recommendation , age]; ///////////////////////////////// } let emissaire=personne(1953); if(emissaire[1]>50) { var rec = emissaire[0]("") // SEXE VIDE. var rec = emissaire[0]("Homme") // Attention! Âge 65 > 50 ans! Veillez à L'ANDROPAUSE var rec = emissaire[0]("Femme") // Attention! Âge 65 > 50 ans! Veillez à LA MÉNOPAUSE } </script> Voyons dans ce dernier cas l’anatomie (la configuration interne) de la variable array « emissaire » : Fonctions Imbriquées - 24 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI Avec la méthode « Object.getOwnPropertyDescriptors(emissaire) » : <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// return [recommendation , age]; ///////////////////////////////// } let emissaire=personne(1953); console.dir(Object.getOwnPropertyDescriptors(emissaire)) // // Object A 0:{ value: ƒ, writable: true, enumerable: true, configurable: true } B 1:{ value: 65, writable: true, enumerable: true, configurable: true } Fonctions Imbriquées - 25 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu C D JavaScript Tome-VI length:{ value: 2, writable: true, enumerable: false, configurable: false } __proto__:Object </script> On peut aussi parcourir (énumérer) les propriétés de l’array « emissaire » avec la commande « for ... in » : <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// return [recommendation , age]; ///////////////////////////////// } let emissaire=personne(1953); for(const key in emissaire){ Fonctions Imbriquées - 26 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(key, emissaire[key]) } /* 0 ƒ recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg = "Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase(… 1 65 */ </script> Maintenant, parcourons l’array retournée, avec un ITÉRATEUR : <script language="JavaScript"> "use strict"; function personne(dn,gender){ let age=(new Date()).getFullYear() - dn function recommendation(sx){ if(!sx) sx=""; if(age>50){ const msg="Attention! Âge "+age+" > 50 ans! Veillez à"; if(sx.toLowerCase().startsWith("m") || sx.toLowerCase().startsWith("h")) { console.log(msg,"l'andropause".toUpperCase()) } else if(sx.startsWith("F")) { console.log(msg,"la ménopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } Fonctions Imbriquées - 27 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI ///////////////////////////////// return [recommendation , age]; ///////////////////////////////// } let ITERABLE=personne(1953); const ITERATOR = ITERABLE[Symbol.iterator](); for(let key in ITERABLE)console.log(ITERATOR.next()) /* Object { value: recommendation(), done: false } Object { value: 65, done: false } */ console.log(ITERATOR.next()) // Object { value: undefined, done: true } console.log(ITERATOR.next()) // Object { value: undefined, done: true } </script> I. Quant à appeler une fonction en cliquant un lien, il y a deux possibilités : 1er L’hypertexte sert seulement à appeler une fonction. La chose est alors très facile : <a href="javascript: console.dir(Object.getOwnPropertyDescriptors(HTMLDivElemen t))"> Without Following Link </a> 2e L’hypertexte DOIT APPELER une fonction mais aussi jouer son rôle habituel, c’est-à-dire « suivre le lien » = aller à un Fonctions Imbriquées - 28 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI emplacement spécifique de la page en cours ou ouvrir la page pointée. Les choses sont alors un peu corsées, mais encore toujours facile : <a href="javascript:my_func('http://diasmath.blogg.org')"> Following Link </a> <script language="JavaScript"> function my_func(s) { console.dir(Object.getOwnPropertyDescriptors(Document)); window.open(s) } </script> II. Si l’hypertexte doit être activé par l’événement « onclick » pour appeler une fonction externe à l’élément ou exécuter un javascript local, son « href » doit être une simple dièse , qu’il doive ou pas suivre de lien. <a href="#" onclick="javascript:my_func('http://diasmath.blogg.org')"> Lien Dièse </a> <script language="JavaScript"> function my_func(s) { console.dir(Object.getOwnPropertyDescriptors(Document)); window.open(s) } </script> Parfois aussi ça marche sans le mot-clé « javascript» : Fonctions Imbriquées - 29 / 31 jeudi, 4. avril 2019 (10:49 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI <a href="#" onclick="my_func('http://diasmath.blogg.org')"> Lien Dièse </a> <script language="JavaScript"> function my_func(s) { console.dir(Object.getOwnPropertyDescriptors(Document)); window.open(s) } </script> Mots-clés : fonctions imbriquées, curry ,closure, objets de première classe, objet Function, callable object, objets de premier ordre, objets de première classe, fonction englobante, variable locale, instances, constructeur, curry, fermeture, closure, getOwnPropertyDescriptors, hypertexte jeudi, 4. avril 2019 (10:49 ). Fonctions Imbriquées - 30 / 31 jeudi, 4. avril 2019 (10:49 ) 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) 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 - 995624714 - 902263541 - 813572818 [email protected] Fonctions Imbriquées - 31 / 31 jeudi, 4. avril 2019 (10:49 )