J.B. Dadet DIASOLUKA Luyalu Nzoyifuanga J AVA S C R I P T (Programmation Internet) V O L . V I +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 première classe « car elles peuvent être manipulées, échangées, avoir des propriétés et des méthodes, comme tout autre objet JS. Une fonction JS, ordinaire soit-elle, est donc ni plus ni moins un objet Function (callable object). Or justement les méthodes sont ni plus ni moins des fonctions. Mais une fonction imbriquée ne peut en principe être appelée que du sein de la fonction qui l’englobe. <script language="JavaScript"> "use strict"; function personne(){ function recommendation(){ console.log( "Hello"); } } console.log(personne()); // undefined //console.log(recommandation()); // Uncaught ReferenceError: // recommandation is not defined console.log(personne.recommandation()); // Uncaught TypeError: // personne.recommandation is not a function J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI </script> 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") || 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); ///////////////////////////////// } Fonctions Imbriquées - 2 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI personne(1953,""); // SEXE VIDE. </script> 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 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); Fonctions Imbriquées - 3 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI personne.rec("Homme"); // Attention! Âge [65] > 50 ans! Veillez  L'ANDROPAUSE </script> 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éthode de la fonction englobante, avec le mot-clé this. 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()) Fonctions Imbriquées - 4 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI } } } } const inst = new personne(1953); 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; Fonctions Imbriquées - 5 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI ///////////////////////////////// } let emissaire=personne(1953); var rec = emissaire("Homme") // Attention! Âge 65 > 50 ans! Veillez  L'ANDROPAUSE var rec = emissaire("Femme") // 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()) } Fonctions Imbriquées - 6 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI else { console.log(msg,"...Sexe Vide.".toUpperCase()) } } else console.log(msg,"...VoTrE jeUnesSe.".toUpperCase()) } return recommendation; } 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> Fonctions Imbriquées - 7 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI 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 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 Fonctions Imbriquées - 8 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI 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 « : Avec la propriété « 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]; ///////////////////////////////// } Fonctions Imbriquées - 9 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI let emissaire=personne(1953); console.dir(Object.getOwnPropertyDescriptors(emissaire)) // // Object A 0:{value: ƒ, writable: true, enumerable: true, config urable: true} B 1:{value: 65, writable: true, enumerable: true, confi gurable: true} C length:{value: 2, writable: true, enumerable: false, configurable: false} D __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()) } Fonctions Imbriquées - 10 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI } } ///////////////////////////////// return [recommendation , age]; ///////////////////////////////// } let emissaire=personne(1953); for(const key in emissaire) 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")) { Fonctions Imbriquées - 11 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI console.log(msg,"la mÂnopause".toUpperCase()) } else { console.log("Sexe Vide.".toUpperCase()) } } } ///////////////////////////////// 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(HTMLDivE lement))"> Without Following Link Fonctions Imbriquées - 12 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI </a> 2e L’hypertexte DOIT APPELER une fonction mais aussi jouer son ràle habituel, c’est-à-dire « suivre le lien » = aller à un 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.or g')"> Lien DiÂse </a> <script language="JavaScript"> function my_func(s) { console.dir(Object.getOwnPropertyDescriptors(Document )); Fonctions Imbriquées - 13 / 15 - mardi, 2. octobre 2018 (12:02 ) J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-VI window.open(s) } </script> Parfois aussi àa marche sans le mot-clà « javascript» : <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, 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 mardi, 2. octobre 2018 (12:02 ). Fonctions Imbriquées - 14 / 15 - mardi, 2. octobre 2018 (12:02 ) 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 diasfb mail2world.com Fonctions Imbriquées - 15 / 15 - mardi, 2. octobre 2018 (12:02 )