javascript tome xvii - Prototype en JavaScript
Transcription
javascript tome xvii - Prototype en JavaScript
L E P R O T O T Y P E e n JAVA / E C M A SCRIPTS J AVA S C R I P T (Programmation Internet) V O L . V Pour Débutants J.B. Dadet DIASOLUKA Luyalu Nzoyifuanga +243 - 851278216 - 899508675 - 991239212 - 902263541 - 813572818 La dernière révision de ce texte est disponible sur CD. CHAPITRE 7 : LE PROTOTYPE : ECMA définit le prototype comme ceci : « object that provides shared properties for other objects ». Le PROTOTYPE d’un objet est la propriété (méthode) native de cet objet qui stocke toutes les valeurs par défaut des propriétés et méthodes natives de cet objet en tant que parent, quand la propriété ou la méthode n’est pas définie dans l’instance. Le prototype est initialement vide au moment de la construction de l’objet. Pour définir des propriétés pour cet objet ou lui en ajouter d’autres, il suffit de les ajouter via son prototype, et automatiquement ces nouvelles propriétés seront partagées avec toutes les instances de cet objet. Bien entendu on peut aussi ajouter directement de nouvelles propriétés à l’objet ou l’une ou l’autre de ces instances, tout simplement en omettant le mot prototype dans la définition de la nouvelle propriété, mais dans ce cas cette nouvelle propriété de l’objet ne sera pas membre du prototype de l’objet et donc ne sera pas héritable (ou partageable avec les instances), donc strictement personnel à ce constructeur ou cette instance. Précipitons un peu les choses, voyons d’emblée comment définir un prototype pour un objet : <script type="text/javascript"> "use strict"; let t=" Object.setPrototypeOf()", l=t.length+5,m=l+5; J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V console.log("".padStart(m,"*")); console.log(t.padStart(l,"*").padEnd(m,"*")); console.log("*".repeat(m)); var dObj = function(){}; console.log(dObj.prototype); // Object { … } // constructor: function dObj() // <prototype>: Object { … } // Deux Instanciations let iObj1 = new dObj(); let iObj_1 = new dObj(); /* 1 */ // Instances iObjx [de dObj] n'ont pas encore de prototype. // On doit leur en créer. // iObj1.prototype.fprot11= _=> //-- FIREFOX: TypeError: //-iObj.prototype is undefined //// //== YANDEX: Uncaught TypeError: //== Cannot set property 'fprot11' of undefined //== at test.html:21 // console.log("iObj1.prototype.fprot11"); console.log(iObj1.prototype); // undefined console.log(Object.getPrototypeOf(iObj1)); // Avec Firefox: // Object { … } // constructor: function dObj() // constructor: dObj() // length: 0 // name: "dObj" // prototype: Object { … } // <prototype>: function () // <prototype>: Object { … } // // Avec Yandex: // {constructor: ƒ} // constructor: ƒ () // arguments: (...) // caller: (...) // length: 0 // name: "dObj" // prototype: {constructor: ƒ} Le Prototype en Java/Ecma-Script 2 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu // // // // JavaScript Tome-V __proto__: ƒ () [[FunctionLocation]]: test.html:8 [[Scopes]]: Scopes[2] __proto__: Object console.log(iObj1.prototype); console.log(iObj_1.prototype); // undefined // undefined /* 2 */ // AJOUT DE PROTOTYPE à L'INSTANCE iObj1 QUI // n'en a pas encore cfr ci-haut. function fprot1(){ Math.PI; } Object.setPrototypeOf ( iObj1, fprot1); // Le prototype de iObj1 n'est plus undefined: console.log(iObj1.prototype); // Object { … } // constructor: function fprot1() // <prototype>: Object { … } // Le prototype de iObj_1 est toujours undefined: console.log(iObj_1.prototype); // undefined /* 3 */ // Ajout propriété propre à l'instance iObj_1 iObj_1.fmetho = function(){ console.log("Ds iObj_1.fmetho"); } iObj_1.fmetho(); // Ds iObj_1.fmetho // La nouvelle méthode propre de iObj_1, // iObj_1.fmetho() n'est Pas accessible à iObj1, // [pourtant] soeur de iObj_1, instances de dObj. // iObj1.fmetho(); // Avec Firefox: TypeError: // iObj1.fmetho is not a function // // Avec Yandex : Uncaught TypeError: // iObj1.fmetho is not a function at test.html:60 </script> Avec Firefox : Le Prototype en Java/Ecma-Script 3 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V ********************************** test.html:4:3 Avec Yandex: Le Prototype en Java/Ecma-Script 4 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Ci-après, nous utiliserons une méthode simple de création de prototype. <script type="text/javascript"> cl=console.log obj_Const=function(pnom,pdaten){ this.K=1000*3600*24*365.2475; this.nom=pnom; this.daten=pdaten; this.age=function(){ return((new Date()-pdaten)/this.K) } } i=new obj_Const("André",new Date("August 1953 11")); for(i in obj_Const.prototype)cl(i); cl("Age = "+i.age()); cl("AJOUT DE PROTOTYPES") obj_Const.prototype.riche=true; // Ajout via prototype obj_Const.sage=false; // Ajout direct (ne se répand pas) obj_Const.prototype.nbfemmes=35; // Ajout via prototype obj_Const.prototype.polygame=function(){ // ---"--if(this.nbfemmes>1)return true; Le Prototype en Java/Ecma-Script 5 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V else return false; }; cl("LISTE DES PROPRIÉTÉS") cl("i.nom="+i.nom); cl("i.age="+i.age()); cl("i.sage="+i.sage); cl("i.riche="+i.riche); cl("i.nbfemmes="+i.nbfemmes) cl("i.polygame="+i.polygame()) cl("\nLES PROTOTYPES AJOUTÉS") for(i in obj_Const.prototype) cl("==> "+i+" = "+obj_Const.prototype[i]); cl(obj_Const.prototype); cl(i.prototype); cl(obj_Const.prototype.constructor); cl(obj_Const.__proto__.constructor); cl("obj_Const.prototype.constructor.length = "+ obj_Const.prototype.constructor.length); </script> Exécution : Age = 64.3917223791744 AJOUT DE PROTOTYPES LISTE DES PROPRIÉTÉS i.nom=André i.age=64.39172237923778 i.sage=undefined i.riche=true i.nbfemmes=35 i.polygame=true LES ==> ==> ==> PROTOTYPES AJOUTÉS riche = true nbfemmes = 35 polygame = function(){ // ---"--if(this.nbfemmes>1)return true; else return false; } Object { riche: true, nbfemmes: 35, polygame: obj_Const.prototype.polygame(), … } Le Prototype en Java/Ecma-Script 6 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V undefined function obj_Const() function Function() obj_Const.prototype.constructor.length = 2 Ajout d’un prototype à un objet : <script type="text/javascript"> "use strict"; Array.prototype.remVal = function(val) { console.log(["Louis", "Morena", "Keriyza", "Louis"]); for (var i = 0, l=this.length; i < l; i++) { if (this[i] === val) { this.splice(i, 1); i--; } } return this; } console.log(["Louis", "Morena", "Keriyza", "Louis"].remVal(2)); </script> Exécution : (4) ["Louis", "Morena", "Keriyza", "Louis"] (2) ["Morena", "Keriyza"] Pour différents modes de création d’objet : <script type="text/javascript"> "use strict"; /* 1 */ console.log( "***AVEC CONSTRUCTEUR, var dObj = function(){}" ) var dObj = function(){} Le Prototype en Java/Ecma-Script 7 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V // Ce constructeur dObj a un prototype implicite console.log(dObj.prototype); // Avec FireFox : Object { … } // Avec Yandex : {constructor: ƒ} // {…} // constructor: function dObj() // fprot11: function fprot11() // fprot12: function fprot12() // fprot32: function fprot32() // fprot35: function fprot35() // <prototype>: Object { … } console.log(Object.getPrototypeOf(dObj)); // Avec FireFox : Object { … } // Avec Yandex : {constructor: ƒ} // () // apply: function apply() // arguments: null // bind: function bind() // call: function call() // caller: null // constructor: function Function() // length: 0 // name: "" // toSource: function toSource() // toString: function toString() // Symbol(Symbol.hasInstance): // function Symbol.hasInstance() // <prototype>: Object { … } // Création de deux instances distinctes de dObj. var iObj1 = new dObj(); var iObj1_ = new dObj(); // Ajout de méthode au prototype du constructeur. dObj.prototype.fprot11= _=> console.log("dObj.prototype.fprot11"); // Appel à partir des instances, de nvelle méthode // du prototype du constructeur. iObj1.fprot11(); // dObj.prototype.fprot11 iObj1_.fprot11(); // dObj.prototype.fprot11 // Ajout de méthode au prototype du Le Prototype en Java/Ecma-Script 8 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V // constructeur du costructeur iObj1.__proto__.fprot12 = _=> console.log("1a. Ds iObj1.__proto__.fprot12"); iObj1.fprot12(); // 1a. Ds iObj1.__proto__.fprot12 iObj1_.fprot12(); // 1a. Ds iObj1.__proto__.fprot12 // Nvelle méthode toujours disponible même à tous // les descendants même de deuxième (et Xième) rang. // L'instance iObj1 [de dObj] n'a pas encore de prototype. // On doit lui en créer. // iObj1.prototype.fprot11= _=> //-- FIREFOX: TypeError: //-iObj.prototype is undefined //// //== YANDEX: Uncaught TypeError: //== Cannot set property 'fprot11' of undefined //== at test.html:12 // console.log("iObj1.prototype.fprot11"); console.log(iObj1.prototype); // undefined console.log(dObj.prototype); // Object { fprot11: fprot11(), fprot12: fprot12(), … } console.log(Object.getPrototypeOf(dObj)); // function () // apply: function apply() // arguments: null // bind: function bind() // call: function call() // caller: null // constructor: function Function() // length: 0 // name: "" // toSource: function toSource() // toString: function toString() // Symbol(Symbol.hasInstance): // function Symbol.hasInstance() // <prototype>: Object { … } // Ajout propriété propre à l’instance iObj1 // avec la méthode « Object.defineProperty() » Object.defineProperty(iObj1, "fprot13", { value: Le Prototype en Java/Ecma-Script 9 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V function() { console.log("1b. Ds iObj1.fprot13") }, enumerable: false, writable: false, configurable: false }); iObj1.fprot13(); // 1b. Ds iObj1.fprot13 // iObj1_.fprot13(); // Pas accessible // [à partir iObj_1, instance jumelle de iObj]. // TypeError: iObj1_.fprot13 is not a function console.log(iObj1_.fprot13); // undefined /* 2 */ console.log( "***AVEC NEW OBJECT(), var iObj2 = new Object()" ) var dObj2 = new Object(); // dObj2 n'est un constructeur ! console.log(dObj2.prototype); // undefined // Essai création d'instance de dObj2. // Refus ! // var iObj2 = new dObj2(); // Firefox: TypeError: dObj2 is not a constructor // // Yandex : Uncaught TypeError: // dObj2 is not a constructor at test.html:83 // Enrichissement direct du prototype de dObj2. // => Refus ! // dObj2.prototype.fprot21= _=> // console.log("iObj2.prototype.fprot21"); // Firefox : TypeError: dObj2.prototype is undefined // // Yandex : Uncaught TypeError: // Cannot set property 'fprot21' of undefined // at test.html:91 Le Prototype en Java/Ecma-Script 10 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V /* 3 */ console.log( "***AVEC LITTERAL D'OBJET (HASH), var iObj3 = {}" ) var dObj3 = {}; // Le constructeur dObj3 n'a pas de prototype natif console.log(dObj3.prototype); // undefined // Création de deux instances distinctes de dObj3. var iObj3 = new dObj(); var iObj3_ = new dObj(); // Enrichissement direct du prototype du constructeur. // => Refus ! // dObj3.prototype.fprot31= _=> // console.log("iObj3.prototype.fprot31"); // Firefox : TypeError: dObj3.prototype is undefined // // Yandex : Uncaught TypeError: // Cannot set property 'fprot31' of undefined // at test.html:119 // Ajout de méthode au prototype du // constructeur du costructeur iObj3.__proto__.fprot32 = _=> console.log("3a. Ds iObj3.__proto__.fprot32"); iObj3.fprot32(); // 3a. Ds iObj3.__proto__.fprot32 iObj3_.fprot32(); // 3a. Ds iObj3.__proto__.fprot32 // Nvelle méthode toujours disponible même à tous // les descendants même de deuxième (et Xième) rang. // L'instance iObj3 [de dObj3] n'a pas encore de prototype. // On doit lui en créer. // iObj3.prototype.fprot33= _=> // console.log("iObj2.prototype.fprot23"); //-- FIREFOX: TypeError: //-iObj3.prototype is undefined //// Le Prototype en Java/Ecma-Script 11 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V //== YANDEX: Uncaught TypeError: //== Cannot set property 'fprot1' of undefined //== at test.html:141 // Ajout propriété propre de l'instance iObj3 // (idem pour iObj3_) iObj3.fprot34= function(){ console.log("3b. Ds iObj3.fprot34"); } iObj3.fprot34(); // 3b. Ds iObj3.fprot34 iObj3_.fprot34= function(){ console.log("3c. Ds iObj3_.fprot34"); } iObj3_.fprot34(); // 3c. Ds iObj3_.fprot34 // Enrichissement du prototype du constructeur // du costructeur de l'instance iObj3. iObj3.__proto__.fprot35 = _=> console.log("3d. Ds iObj3.__proto__.fprot35"); iObj3.fprot35(); // 3d. Ds iObj3.__proto__.fprot35 iObj3_.fprot35(); // 3d. Ds iObj3.__proto__.fprot35 // Ajout de propriété (méthode) propre à l'instance iObj3 iObj3.fprot36= function(){ console.log("3e. Ds iObj3.fprot36"); } iObj3.fprot36(); // 3e. Ds iObj3.fprot36 // iObj3_.fprot36(); // Avec Firefox : TypeError: // iObj3_.fprot36 is not a function // // Avec Yandex : Uncaught TypeError: // iObj3_.fprot36 is not a function // at test.html:179 /* 4 */ Le Prototype en Java/Ecma-Script 12 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V console.log( "***AVEC OBJECT.CREATE, let pObj = _ => {}" ) let dObj4 = _ => {} // Ce constructeur dObj n'a pas de prototype natif console.log(dObj4.prototype); // undefined // Création de deux instances distinctes de dObj. let iObj4 = Object.create(dObj4); let iObj4_ = Object.create(dObj4); // Essai Ajout de méthode au prototype du constructeur. // dObj4.prototype.fprot41= _=> // console.log("dObj4.prototype.fprot41"); // Firefox: TypeError: dObj4.prototype is undefined // // Yandex : Uncaught TypeError: // Cannot set property 'fprot41' of undefined // at test.html:206 // Appel à partir des instances, de nvelle méthode // du prototype du constructeur. // iObj4.fprot41(); // iObj4_.fprot41(); // Firefox : TypeError: // iObj4.fprot41 is not a function // // Yandex: Uncaught TypeError: // iObj4.fprot41 is not a function // at test.html:216 // Ajout de méthode au prototype du // constructeur du costructeur iObj4.__proto__.fprot42 = _=> console.log("4a. Ds iObj4.__proto__.fprot42"); iObj4.fprot42(); // 4a. Ds iObj4.__proto__.fprot42 iObj4_.fprot42(); // 4a. Ds iObj4.__proto__.fprot42 // Nvelle méthode toujours disponible même à tous // les descendants même de deuxième (et Xième) rang. // L'instance iObj4 [de dObj4] n'a pas encore de prototype. // On doit lui en créer. // iObj4.prototype.fprot43= _=> // console.log("iObj4.prototype.fprot43"); Le Prototype en Java/Ecma-Script 13 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V //-- FIREFOX: TypeError: //-iObj.prototype is undefined //// //== YANDEX: Uncaught TypeError: //== Cannot set property 'fprot43' of undefined //== at test.html:238 console.log(iObj4.prototype); console.log(dObj4.prototype); // undefined // undefined // Ajout propriété propre de la seule instance iObj4 iObj4.fprot44= function(){ console.log("4b. Ds iObj4.fprot44"); } iObj4.fprot44(); // 4b. Ds iObj4.fprot44 console.log(iObj4_.fprot44); // undefined </script> console.log(Object.getOwnPropertyDescriptors(dObj4)) // Object { fprot42: {…}, length: {…}, name: {…} } // fprot42: Object {} AVEC FIREFOX // fprot42: Object {} AVEC YANDEX Le Prototype en Java/Ecma-Script 14 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V // name: Object {} AVEC FIREFOX // name: Object {} AVEC YANDEX // length: Object {} AVEC FIREFOX // length: Object {} AVEC YANDEX Le Prototype en Java/Ecma-Script 15 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V // prototype: Object {} AVEC FIREFOX // prototype: Object {} AVEC YANDEX console.log(Object.getOwnPropertyDescriptors(iObj1)) // Object { fprot13: {…} } // AVEC FIREFOX Le Prototype en Java/Ecma-Script 16 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V // AVEC YANDEX Exécution : Le Prototype en Java/Ecma-Script 17 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Nous avons vu dans le code ci-dessus comment définir une nouvelle propriété d’un objet, selon le modèle suivant : <script type="text/javascript"> `use strict`; const objet={}; console.dir(Object.getOwnPropertyDescriptors(objet)); Le Prototype en Java/Ecma-Script 18 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V const v="30 Nov 2018" Object.defineProperty(objet, 'newProp', { // Property Descriptor value: v, configurable: true, enumerable: true, writable: true } ); console.dir(objet); console.dir(Object.getOwnPropertyDescriptors(objet)); </script> Voici comment ajouter plusieurs nouvelles propriétés en une seule opération : <script type="text/javascript"> `use strict`; let objet={}; console.dir(Object.getOwnPropertyDescriptors(objet)); Le Prototype en Java/Ecma-Script 19 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V const v="30 Nov 2018" objet = Object.defineProperties({}, // Dummy Object. { // Property Descriptors 'newProp1': // Une des Property Descriptors { value: v, configurable: true, enumerable: true, writable: true }, 'newProp2': // Une autre Property Descriptor { value: "22h10h", configurable: true, enumerable: true, writable: false // *************** } } ); console.dir(objet); console.dir(Object.getOwnPropertyDescriptors(objet)); objet.newProp1 = "New Value"; objet.newProp2 = "Non writable"; // Aucune alerte ! console.dir(objet); console.dir(Object.getOwnPropertyDescriptors(objet)); </script> Le Prototype en Java/Ecma-Script 20 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V La chaîne du prototype : JavaScript est un langage basé sur le prototype (prototype-based language). On préfère même dire que c’est un système basé sur la délégation (delegation-based system), c’est-à-dire que chaque objet a une chaîne de prototype (prototype chain) : Quand vous tentez d’accéder à une propriété ou méthode d’un objet (en cours de création ou d’instanciation ou une instance d’objet), il se passe ceci : 1. Si cette propriété existe comme telle dans l’objet en soi, elle est récupérée ; 2. Si cette propriété n’existe pas en soi dans cet objet, elle est cherchée dans le prototype de l’object ; le prototype est un objet délégué (delegate object) c’est-à-dire que la recherche de la propriété est déléguée à l’objet « prototype » (prototype object) qui est une propriété de l’objet manipulé. Si l’objet prototype possède la propriété cherchée, Le Prototype en Java/Ecma-Script 21 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V celle-ci est récupéré, sinon elle est éventuellement cherchée dans le prototype du prototype, 3... Ainsi de suite la recherche se poursuit (chaîne du prototype) jusqu’à l’objet racine souvent le Object (avec « O » majuscule) et éventuellement son prototype (prototype de l’objet racine =root prototype) souvent le prototype de Object « Object.prototype ». <script type="text/javascript"> "use strict"; // Constructeur AVEC SA PROPRE toString(). function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } console.log(dObj1); // function dObj1() console.log(""+dObj1); /* function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } */ let iObj1=new dObj1(); // iObj1 n'a pas de toString() propre // => chaîne de prototype vers son constructeur // dObj1.toString() ou dObj1.prototype.toString() console.log(iObj1); // Object { toString: toString() } console.log(""+iObj1); // ... dans dObj1.toString() console.log("*AAAAA* "+dObj1); /* *AAAAA* function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } */ console.log("*AAAAA* "+dObj1.__proto__.toString()); // *AAAAA* function () {} Le Prototype en Java/Ecma-Script 22 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V console.log("*BBBBB* "+iObj1); // *BBBBB* Object { toString: toString() } console.log("*DDDDD* "+iObj1.__proto__.toString()); // *DDDDD* [object Object] // Constructeur SANS toString() PROPRE function dObj2() { // Pas de propriété toString() propre } console.log(dObj2); // function dObj2() console.log(""+dObj2); /* function dObj2() { // Pas de propriété toString() propre } */ let iObj2=new dObj2(); // iObj2 n'a pas de toString() propre // ni son constructeur => chaîne de prototype // vers toString du constructeur du constructeur // ou du prototype du constructeur du constructeur. console.log(iObj2); // bject { } console.log(""+iObj2); // [object Object] console.log("*AAAAA* "+dObj2); /* *AAAAA* function dObj2() { // Pas de propriété toString() propre } */ console.log("*AAAAA* "+dObj2.__proto__.toString()); // *AAAAA* function () {} console.log("*BBBBB* "+iObj2); // *BBBBB* [object Object] console.log("*DDDDD* "+iObj2.__proto__.toString()); Le Prototype en Java/Ecma-Script 23 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu // JavaScript Tome-V *DDDDD* [object Object] // Constructeur SANS toString() PROPRE, // mais ayant toString() dans son prototype. function dObj3() { } dObj3.prototype.toString=_=> console.log("toString de protot ype") // toString de prototype console.log(dObj3); // function dObj3() console.log(""+dObj3); // function dObj3() {} let iObj3=new dObj3(); // iObj3 n'a pas de toString() propre // ni son constructeur => chaîne de prototype // vers toString du constructeur du constructeur // ou du prototype du constructeur du constructeur. console.log(iObj3); // Object { } console.log(""+iObj3); // undefined console.log("*AAAAA* "+dObj3); // *AAAAA* function dObj3() {} console.log("*AAAAA* "+dObj3.__proto__.toString()); // *AAAAA* function () {} console.log("*BBBBB* "+iObj3); // *BBBBB* undefined console.log("*DDDDD* "+iObj3.__proto__.toString()); // *DDDDD* undefined // APPEL DE CONSTRUCTEUR ET OBJET COMME FONCTIONS ORDINAIRES // TypeError: this is undefined test.html:4:8 // dObj1 file:///K:/DADET/PROGS/test.html:4:8 // <anonyme> file:///K:/DADET/PROGS/test.html:121:10 Le Prototype en Java/Ecma-Script 24 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V ///////// dObj1(); // // TypeError: iObj1 is not a function test.html:124:10 ///////// iObj1(); // CHRONOLOGIE DES EXÉCUTIONS AVEC MAXTHON: /* 2018-02-25 15:33:08.364 test.html:8 function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } 2018-02-25 15:33:08.386 test.html:10 function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } 2018-02-25 15:33:08.386 test.html:21 dObj1 {} 2018-02-25 15:33:08.388 test.html:23 ... dans dObj1.toString() 2018-02-25 15:33:08.388 test.html:26 *AAAAA* function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } 2018-02-25 15:33:08.388 test.html:33 *AAAAA* function () {} 2018-02-25 15:33:08.388 test.html:36 *BBBBB* ... dans dObj1.toString() 2018-02-25 15:33:08.389 test.html:39 *DDDDD* [object Object] 2018-02-25 15:33:08.389 test.html:48 dObj2() { // Pas de propriété toString() propre } 2018-02-25 15:33:08.389 test.html:50 function dObj2() { // Pas de propriété toString() propre } 2018-02-25 15:33:08.389 test.html:61 dObj2 {} 2018-02-25 15:33:08.389 test.html:63 Le Prototype en Java/Ecma-Script 25 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V [object Object] 2018-02-25 15:33:08.389 test.html:66 *AAAAA* function dObj2() { // Pas de propriété toString() propre } 2018-02-25 15:33:08.390 test.html:72 *AAAAA* function () {} 2018-02-25 15:33:08.390 test.html:75 *BBBBB* [object Object] 2018-02-25 15:33:08.390 test.html:78 *DDDDD* [object Object] 2018-02-25 15:33:08.390 test.html:89 dObj3() {} 2018-02-25 15:33:08.390 test.html:91 function dObj3() {} 2018-02-25 15:33:08.390 test.html:99 dObj3 {} 2018-02-25 15:33:08.390 test.html:86 toString de prototype 2018-02-25 15:33:08.390 test.html:101 undefined 2018-02-25 15:33:08.390 test.html:104 *AAAAA* function dObj3() {} 2018-02-25 15:33:08.390 test.html:107 *AAAAA* function () {} 2018-02-25 15:33:08.391 test.html:86 toString de prototype 2018-02-25 15:33:08.391 test.html:110 *BBBBB* undefined 2018-02-25 15:33:08.391 test.html:86 toString de prototype 2018-02-25 15:33:08.391 test.html:113 *DDDDD* undefined */ </script> CHRONOLOGIE DES EXÉCUTIONS AVCE FIREFOX : function dObj1() test.html:8:4 function dObj1() { this.toString=_=> "... dans dObj1.toString()"; Le Prototype en Java/Ecma-Script 26 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V return("Un Objet retourne sa propre copie.") } test.html:10:4 Object { toString: toString() } test.html:21:4 ... dans dObj1.toString() test.html:23:4 *AAAAA* function dObj1() { this.toString=_=> "... dans dObj1.toString()"; return("Un Objet retourne sa propre copie.") } test.html:26:4 *AAAAA* function () { } test.html:33:4 *BBBBB* ... dans dObj1.toString() test.html:36:4 *DDDDD* [object Object] test.html:39:4 function dObj2() test.html:48:4 function dObj2() { // Pas de propriété toString() propre } test.html:50:4 Object { } test.html:61:4 [object Object] test.html:63:4 *AAAAA* function dObj2() { // Pas de propriété toString() propre } test.html:66:4 *AAAAA* function () { } test.html:72:4 *BBBBB* [object Object] test.html:75:4 *DDDDD* [object Object] test.html:78:4 function dObj3() test.html:89:4 function dObj3() { } test.html:91:4 Object { } test.html:99:4 toString de prototype test.html:86:33 undefined test.html:101:4 *AAAAA* function dObj3() { } test.html:104:4 *AAAAA* function () { } test.html:107:4 toString de prototype test.html:86:33 *BBBBB* undefined test.html:110:4 toString de prototype test.html:86:33 *DDDDD* undefined test.html:113:4 Le prototype est comme une banque des propriétés par défaut de l’objet et surtout ses instances, pouvant donc être partagées avec les descendants (instances) de cet objet. Mais en plus des propriétés du prototype, Le Prototype en Java/Ecma-Script 27 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V l’objet peut avoir ses propriétés propres non stockées dans le prototype (propriétés non membres de son prototype). En d’autres termes : Toute propriété du prototype d’un objet appartient aussi à cet objet, mais certaines propriétés de l’objet ne sont pas nécessairement propriétés de son prototype (et donc sont non héritables), une instance d’objet pouvant aussi avoir des « ownProperties ». Implications de la chaîne de prototype : Considérons cet objet parent (constructeur) : <script type="text/javascript"> "use strict"; let oParent = function(p){ } // objet vide avec prototype implicite, vide. </script> Créons deux instances de cet objet parent oParent, comme suit : <script type="text/javascript"> "use strict"; let iObjet1 = new oParent(); <script type="text/javascript"> "use strict"; function oParent(){ } let iObjet1 = new oParent(); let iObjet2 = new oParent(); // Ajoutons une propriété // dans le prototype du constructeur oParent.prototype.distance={ par_avion:"1000 km", par_route:"2500km" } console.log(iObjet1.distance); Le Prototype en Java/Ecma-Script 28 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V console.log(iObjet2.distance); </script> Les deux instances iObjet1 et iObjet2 héritent automatiquement de cette nouvelle propriété définie dans le prototype de l’objet parent. Par exemple, les deux instances afficheront distance.par_avion = 1000 km : Exécution du programme : Object { par_avion: "1000 km", par_route: "2500km" } test.html:15:4 Object { par_avion: "1000 km", par_route: "2500km" } test.html:16:4 Exécution à la console du browser : console.log(iObjet1.distance.par_avion); console.log(iObjet2.distance.par_avion); console.log(iObjet1.distance.par_route); console.log(iObjet2.distance.par_route); En tapant ceci à la console du browser : iObjet1.distance.par_avion iObjet2.distance.par_avion iObjet2.distance.par_route iObjet1.distance.par_route "1000 km" "1000 km" "2500km" "2500km" console.log(iObjet1.distance.par_avion) debugger eval code:1:1 undefined 1000 km console.log(iObjet2.distance.par_avion) 1000 km Le Prototype en Java/Ecma-Script 29 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V debugger eval code:1:1 undefined console.log(iObjet1.distance.par_route) debugger eval code:1:1 undefined 2500km console.log(iObjet2.distance.par_route) debugger eval code:1:1 undefined 2500km Si nous redéfinissons la distance pour l’instance par exemple seulement celle de iObjet2, comme ceci : iObjet2.distance.par_route = "3500 km"; Comme iObjet2 n’a pas la propriété distance parmi ses OwnProperties, l’ordinateur considérera que c’est la propriété distance du prototype du parent (constructeur) que l’on a voulu modifier, et modifiera donc ce prototype du constructeur, et l’effet se manifestera à toutes les instances du constructeur. Ainsi donc, en tentant d’afficher la distance par_route de l’instance iObjet1, c’est la distance redéfinie pour l’objet iObjet2 (3500 km) qui sera affichée. Si on avait défini la distance comme une propriété-objet comme ceci, elle serait automatiquement considérée comme propriété propre (faisant partie seulement) de iObjet2 : iObjet2.distance={ par_avion : "1750 km", par_route : "3500 km" } console.log(iObjet1.distance.par_avion); // 1000 km console.log(iObjet2.distance.par_avion); // 1750 km Le Prototype en Java/Ecma-Script 30 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V console.log(iObjet1.distance.par_route); // 3500 km console.log(iObjet2.distance.par_route); // 3500 km Le tout donne : <script type="text/javascript"> "use strict"; let oParent = function(p){ } // objet vide avec prototype implicite, vide. let iObjet1 = new oParent(); let iObjet2 = new oParent(); oParent.prototype.distance={ par_avion:"1000 km", par_route:"2500km" } console.log(iObjet1.distance.par_avion); console.log(iObjet2.distance.par_avion); console.log(iObjet1.distance.par_route); console.log(iObjet2.distance.par_route); // // // // 1000 km 1000 km 2500km 2500km // // // // 1000 1000 3500 3500 km km km km // // // // 1000 1000 3500 3500 km km km km iObjet2.distance.par_route = "3500 km"; console.log(iObjet1.distance.par_avion); console.log(iObjet2.distance.par_avion); console.log(iObjet1.distance.par_route); console.log(iObjet2.distance.par_route); iObjet2.distance={ par_avion : "1750 km", par_route : "3500 km" } console.log(iObjet1.distance.par_avion); console.log(iObjet2.distance.par_avion); console.log(iObjet1.distance.par_route); console.log(iObjet2.distance.par_route); </script> Le Prototype en Java/Ecma-Script 31 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Dans la dissection ci-dessous nous voyons que le prototype dépend du fait que notre constructeur ait des paramètres formels ou pas, et s’il comporte des « this » ou pas, peu importe s’il est instancié. Un constructeur sans « this » est une fonction ordinaire, mais bien entendu une fonction est bel et bien un objet). I. Sans paramètres formels avec ou sans « this » et même avec un corps vide : <script type="text/javascript"> 'use strict'; // Fonction ordinaire function dObj(){ var fdObj = function(){ return("Insiding dObj.fdObj") } } console.log(dObj) </script> Nous voyons dans la console de FireFox que le prototype implicite (par défaut) de notre fonction est l’objet objet, et celui de son parent est [aussi] une fonction. function dObj() dObj() length: 0 name: "dObj" prototype: Object { … } __proto__: function () En déroulant ses éléments dans la console, nous obtenons ceci : Dans le prototype par défaut de notre fonction dObj() celle-ci est bel et bien un/le constructeur. dObj() length: 0 Le Prototype en Java/Ecma-Script 32 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V name: "dObj" prototype: {…} constructor: function dObj() __proto__: Object { … } __proto__: () apply: function apply() arguments: null bind: function bind() call: function call() caller: null constructor: function Function() isGenerator: function isGenerator() length: 0 name: "" toSource: function toSource() toString: function toString() Symbol(Symbol.hasInstance): undefined __proto__: Object { … } Son constructeur est un objet [__proto__ du prototype de dObj : « dObj() - prototype: (...) - __proto__ »] est Object. En déroulant ce __proto__ nous voyons que le constructeur de ce prototype est la fonction Object() que nous savons être un objet (l’objet parent de tous les autres objets). Nous voyons qu’il n’est pas affiché le __proto__ (parent) de Object : l’objet objet n’a pas de parent, il n’est fils de rien.. prototype: Object { … } prototype: {…} constructor: function dObj() __proto__: {…} __defineGetter__: function __defineGetter__() __defineSetter__: function __defineSetter__() __lookupGetter__: function __lookupGetter__() __lookupSetter__: function __lookupSetter__() constructor: function Object() hasOwnProperty: function hasOwnProperty() isPrototypeOf: function isPrototypeOf() propertyIsEnumerable: function propertyIsEnumerable() Le Prototype en Java/Ecma-Script 33 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V toLocaleString: function toLocaleString() toSource: function toSource() toString: function toString() unwatch: function unwatch() valueOf: function valueOf() watch: function watch() Nous pouvons aussi y voir les autres propriétés du prototype de cet Object parent du prototype de dObj : function __defineGetter__(), function __defineSetter__(), function __lookupGetter__(), function __lookupSetter__(), constructor: function Object() function hasOwnProperty(), function isPrototypeOf(), function propertyIsEnumerable(), function toLocaleString(), function toSource(), function toString(), function unwatch(), function valueOf(), function watch() Nous avons vu là, le prototype du constructeur du prototype implicite de notre fonction dObj() (qui est en fait aussi un objet). Voyons maintenant le prototype du constructeur de notre fonction dObj() : « dObj() __proto__ » : Nous y voyons que le constructeur de notre fonction est une fonction (__proto__: function ()). Déroulons ce prototype du parent : Nous voyons que le constructeur de ce parent est une fonction, la fonction Function (avec « F » majuscule, qui est aussi bien entendu un objet, le constructeur [pas « parent »] de l’objet Object et de la fonction Functiont). Ce constructeur parent a un __proto__ (comprenez « prototype du parent » ou tout simplement « le parent »), comme on peut le voir cidessous, qui est l’objet Object, parent de tous les objets y compris les fonctions (comme on le constate ici). Le Prototype en Java/Ecma-Script 34 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Mais attention, ne confondez pas l’objet générique « Object » et l’objet global « window » qu’on peut nommer ou pas et qui renferme entre autres les propriétés suivantes : Infinity , NaN , undefined , eval() , isFinite() , isNaN() , parseFloat() , parseInt() , decodeURI() , decodeURIComponent() , encodeURI() , encodeURIComponent() , Math , JSON , Reflect , Object() , Function() , Boolean() , Number() , String() , Symbol() , Array() , Float32Array() , Float64Array() , Int8Array() , Int16Array() , Int32Array() , Uint8Array() , Uint8ClampedArray() , Uint16Array() , Uint32Array() , ArrayBuffer() , DataView() , Date() , RegExp() , Set() , WeakSet() , Map() , WeakMap() , Proxy() , Promise() , Error() , SyntaxError() , RangeError() , TypeError() , ReferenceError() , URIError() , EvalError(). Il n’est pas nécessaire de retenir par coeur cette liste partielle (mais il faut connaître leur existence), vous pouvez obtenir la liste exhaustive à la console du navigateur en tapant « Object.getOwnPropertyNames(window) ». Baidu en liste 591, Maxthon 753, UC Browser 771, Torch 781, FireFox 794, Yandex 807, Google Chrome 808, Vivaldi 809, Opera 813, Brave 814, UR Brower 831,... Toutes les propriétés de l’objet global window sont disponibles (=accesibles) directement de partout sans préfixer du nom d’objet « window ». Dans l’espace global (càd en dehors de toute fonction), « this » est l’alias de « window ». __proto__: () apply: function apply() arguments: null bind: function bind() call: function call() caller: null constructor: function Function() Le Prototype en Java/Ecma-Script 35 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V isGenerator: function isGenerator() length: 0 name: "" toSource: function toSource() toString: function toString() Symbol(Symbol.hasInstance): undefined __proto__: Object { … } En déroulant le constructeur « function Function » nous pouvons voir ses propriétés dont encore un __proto__ qui est une fonction : constructor: Function() length: 1 name: "Function" __proto__: function () En déroulant ce __proto__: function() (= prototype du constructeur et qui est une fonction) nous obtenons : __proto__: () apply: function apply() arguments: null bind: function bind() call: function call() caller: null constructor: function Function() isGenerator: function isGenerator() length: 0 name: "" toSource: function toSource() toString: function toString() Symbol(Symbol.hasInstance): undefined __proto__: Object { … } Les propriétés de cet objet Function sont donc : Méthodes : function apply(), function bind(), function call(), function Function(), function isGenerator(), function toSource(), function toString(), Le Prototype en Java/Ecma-Script 36 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Propriétés : arguments: null, caller: null, length: 0, name: "", Symbol(Symbol.hasInstance): undefined En déroulant ce __proto __ : Object {...} nous tombons de nouveau sur l’objet Object qui n’a pas de __proto__ donc pas de parent (pas de constructeur). II. Avec des paramètres formels avec ou sans « this » : Notre fonction dObj() n’a aucun prototype même pas le prototype par défaut, donc aucune propriété initiale. Mais il a un __proto__ qui est le même constructeur que la forme sans paramètres. Le Prototype en Java/Ecma-Script 37 / 38 jeudi, 4. avril 2019 J.D.B. DIASOLUKA Nz. Luyalu JavaScript Tome-V Kinshasa, le 4 avril 2019 (10:47 ). Mots-clés : Void, chaîne du prototype, JavaScript, prototype, prototype-based language, délégation, delegation-based system, prototype chain, objet délégué, delegate object, objet prototype, prototype object, objet racine, root prototype, Object.prototype 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] Le Prototype en Java/Ecma-Script 38 / 38 jeudi, 4. avril 2019