javascript tome iii
Transcription
javascript tome iii
J.B. Dadet DIASOLUKA Luyalu Nzoyifuanga JA V ASCRIPT VOL. III +243 - 851278216 - 899508675 - 991239212 - 902263541 - 813572818 La dernière révision de ce texte est disponible sur CD. CHAPITRE 6 : Quelques notions importantes à savoir : I. Portée du mode strict : La portée du mode strict se limite à celle de l’élément SCRIPT ou de la fonction dans lesquels ce mode a été activé. <script type="text/javascript"> "use strict"; ///////// nondecl=45; // ReferenceError: // assignment to undeclared variable nondecl </script> <script type="text/javascript"> non_decl=50; console.dir(non_decl) // 50 // "use strict" ne s’est pas étendu à cet élément. function fstrict(){ "use strict"; ///////// nondecl=54; // ReferenceError: // assignment to undeclared variable nondecl } fstrict(); function freguliere(){ non_decl=500; console.dir(non_decl) // 500 // "use strict" ne s’étend à cette fonction. } freguliere(); </script> II. Classes en JavaScript : Contrairement aux langages C/C++, JS ne possède pas les types de données enum, structure...., et même les objets en JS ne sont pas des classes comme dans C++. https://www.ecma-international.org/ecma-262/5.1 ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects. An ECMAScript object is a collection of properties each with zero or more attributes that determine how each property can be used—for example, when the Writable attribute for a property is set to false, any attempt by executed ECMAScript code to change the value of the property fails. Properties are containers that hold other objects, primitive values, or functions. A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, and String; an object is a member of the remaining built-in type Object; and a function is a callable object. A function that is associated with an object via a property is a method. ECMAScript defines a collection of built-in objects that round out the definition of ECMAScript entities. These built-in objects include the global object, the Object object, the Function object, the Array object, the String object, the Boolean object, the Number object, the Math object, the Date object, the RegExp object, the JSON object, and the Error objects Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError and URIError. JS est un langage de programmation orienté objet (OOP) dans lequel TOUT sauf les valeurs primitives est objet (c’est-à-dire nativement doté ou pouvant à tout moment être doté de membres [ intrinsèques ] : propriétés représentant des valeurs et méthodes = fonctions). Un membre particulier ou propriété particulière des objets JS c’est le prototype qui est une propriété au sens OOP figurant une bibliothèque des propriétés héritables de l’objet en cours. Dans certains langages de programmation les membres des objets complexes (appelons ces objets « structures ») sont aussi appelés « attributs ». Techniquement, en JavaScript « attribut » réfère à une caractéristique particulière d’une propriété (attribute : internal value that defines some characteristic of a property - https:/www.ecma-international.org/ecma-262/8.0). Mais qui a dit que syntactiquement en JS les classes au look C++, Smalltalk, ou Java (ou class-iques dit-on) n’existent pas, seuls les objets et leurs prototypes ? Depuis le standard ECMAScript 2015 (ES6) JS dispose d’une syntaxe spéciale « class » permettant de plus facilement créer des objets et manipuler leurs prototypes et donc l’héritage. En fait, class en JS est simplement une syntaxe spéciale pour définir d’un coup un constructeur et les méthodes (pas les propriétés) de son prototype. En réalité une class JS n’est ni plus ni moins une fonction : il n’existe pas d’entité spécifique class en JavaScript. J.D.B. DIASOLUKA Nz. Luyalu 2 / 16 JavaScript Tome-III <script type="text/javascript"> "use strict"; let notreClass = class nomClasse {} console.log(notreClass) // function nomClasse() [FIREFOX] // class nomClasse {} [YANDEX] console.log(typeof notreClass) // function </script> On introduit une définition de classe avec le mot clé « class », et le constructeur d’une classe ne peut jamais être appelé sans « new ». Par défaut, le constructeur d’une classe est une fonction vide. Version class, sans prototype explicitement défini : <script type="text/javascript"> "use strict"; class Person { constructor(id) { this.id = id; } congrat() { console.log("Hello,",this.id); // Hello, Brejnev. } } let president = new Person("Brejnev."); president.congrat(); </script> Version objet : il faut définir explicitement le prototype. <script type="text/javascript"> "use strict"; function Person(id) { this.id = id; } Person.prototype.congrat = function() { console.log("Hello,",this.id); } let president = new Person("Brejnev."); // president hérite de la méthode congrat // via le prototype. president.congrat(); // Hello, Brejnev. </script> En fait, l’identifiant de la classe est aussi la fonction constructeur. J.D.B. DIASOLUKA Nz. Luyalu 3 / 16 JavaScript Tome-III <script type="text/javascript"> "use strict"; var vClass = class ClassName { constructor(p) { this.id=p; }; fct(){console.log("Hello")} } console.log(vClass === vClass.prototype.constructor); // true console.log( Object.getOwnPropertyNames(vClass.prototype)); // Array [ "constructor" , "fct" ] </script> Une classe JS possède, en plus des propriétés et méthodes comme dans les objets, un constructeur. Les corps des classes utilisent automatiquement le mode strict, le corps des classes (pour les expressions et les déclarations de classes) est exécuté en mode strict (càd que la méthode constructeur, les méthodes statiques, le prototype, les accesseurs [getters] et les mutateurs [setters] sont exécutés en mode strict). Les fonctions liées aux classes sont exécutées en mode strict quel que soit le mode de JS. Un « constructor » permet de créer et d'initialiser les objet. Lors de la création d’un objet, l’objet lui-même est son propre constructeur. Le constructeur d’une classe est explicite et doit être unique. <script type="text/javascript"> "use strict"; class imc { constructor(pds,tHt) { this.icorp = pds / Math.pow(tHt,2); } } let dias=new imc(60,1.65) console.log(dias.icorp.toFixed(2),"kg/m2"); // 22.04 kg/m2 </script> Exemple 2 : On peut utiliser une expression de classe. Expression simple : J.D.B. DIASOLUKA Nz. Luyalu 4 / 16 JavaScript Tome-III <script type="text/javascript"> "use strict"; var Polygone = class { constructor(longueur, largeur) { this.nom = 'Polygone'; this.longueur = longueur/2; this.largeur = largeur/2; this.surf=(this.longueur*2)*(this.largeur*2); this.qsurf=this.longueur*this.largeur; } } let rect = new Polygone(10,15); console.log("1/4 Surf=",rect.longueur*rect.largeur); // 1/4 Surf= 37.5 console.log("1/4 Surf=",rect.qsurf); // 1/4 Surf= 37.5 console.log("Surf=",rect.surf); // Surf= 150 console.log("========="); console.log(Polygone); </script> Ex Exécution cution : test.html:12 22:17:18.784 22:17:18.784 22:17:18.784 22:17:18.784 1/4 Surf= 37.5 test.html:13 1/4 Surf= 37.5 test.html:14 Surf= 150 test.html:15 ========= test.html:16 class Polygone {} Expression de classe, nommée : permet de faire référence à la classe, au sein du corps de la classe. Ce nom de classe ne sera visible que du sein de la portée de l'expression de classe. <script type="text/javascript"> "use strict"; var vClass = class ClassName { constructor() {} leNom() { return ClassName.name; } } var i = new vClass; console.log(i.leNom()); // ClassName ///////// console.log(ClassName.name); // ReferenceError: ClassName is not defined console.log(vClass.name); J.D.B. DIASOLUKA Nz. Luyalu 5 / 16 // ClassName JavaScript Tome-III </script> Syntaxe générale : var MaClasse = class [nomClasse] [extends] { // corps de la classe }; Le mot-clé « extends » (dans les déclarations ou les expressions de classes) permet de créer une classe héritière d'une autre (« sousclasse » ou « classe-fille »). <script type="text/javascript"> "use strict"; class Animal { constructor(nom) { this.nom = nom; } parle() { return(this.nom + ' fait du bruit.'); } } class Chien extends Animal { parle() { return(this.nom + ' croque un os.'); // Chien hérite de « nom » dans Animal. } } let iAnimal = new Animal("Milou"); console.log(iAnimal.parle()); // Milou fait du bruit. let iChien = new Chien("Binky"); console.log(iChien.parle()); // Binky croque un os. </script> Les mots-clé « extends » et « super » : <script type="text/javascript"> "use strict"; class Polygone { constructor(hauteur, largeur) { J.D.B. DIASOLUKA Nz. Luyalu 6 / 16 JavaScript Tome-III this.nom = 'Polygone'; this.hauteur = hauteur; this.largeur = largeur; this.tSurf="Haut="+this.hauteur+ ", Larg="+this.largeur this.Surf=this.tSurf+" => "+ this.hauteur*this.largeur } calc(){ return "Surf "+ this.nom+": "+this.Surf } } class Carré extends Polygone { constructor(longueur) { super(longueur); this.nom = 'Carré'; this.tSurf="Longueur="+longueur this.Surf=this.tSurf+" => "+ Math.pow(longueur,2); } } class Volume extends Carré { constructor(longueur,largeur,hauteur) { super(longueur,largeur,hauteur); this.nom = 'Volume'; this.tVol="Haut="+hauteur+", Larg="+ largeur+", Long="+longueur this.Vol=this.tVol+" => "+ longueur*largeur*hauteur; } calc(){return this.nom+": "+this.Vol} } let iPolyg = new Polygone(10,20); console.log(iPolyg.calc()); // Surf Polygone: Haut=10, Larg=20 => 200 let iSurf = new Carré(17); console.log(iSurf.calc()); // Surf Carré: Longueur=17 => 289 let iVol = new Volume(3,5,7); console.log(iVol.calc()); // Volume: Haut=7, Larg=5, Long=3 => 105 </script> J.D.B. DIASOLUKA Nz. Luyalu 7 / 16 JavaScript Tome-III Appel d’une méthode du parent (super) à partir d’une classe fille : <script type="text/javascript"> "use strict"; function Voiture (nom) { this.nom = nom; } Voiture.prototype.roule = function () { console.log(this.nom + ' file très vite.'); // Ferari file très vite. } class deRally extends Voiture { roule() { super.roule(); // Ferari file très vite (ligne 6). console.log(this.nom + ' chancelle.'); // Ferari chancelle. } } let v = new deRally('Ferari'); v.roule(); </script> Prototype et « super » ! <script type="text/javascript"> "use strict"; var Voiture = { roule() { console.log(this.nom + ' file très vite.'); } }; class deRally { constructor(nom) { this.nom = nom; } roule() { super.roule(); console.log(this.nom + ' traîne.'); } } Object.setPrototypeOf(deRally.prototype, Voiture); // Donne accès aux méthodes de Voiture. J.D.B. DIASOLUKA Nz. Luyalu 8 / 16 JavaScript Tome-III var d = new deRally('Ferari'); d.roule(); </script> Les classes peuvent inclure des getters et des setters : <script type="text/javascript"> "use strict"; class User { constructor(idName) { console.log("Ds constructor."); this.idName = idName; // invoque le setter } get idName() { console.log(this._idName,"- de get"); return this._idName; } set idName(value) { console.log("Ds setter."); if (value.length < 4) { console.log("idName trop court."); return; } this._idName = value; } } console.log('Avant let user=new User("John")'); let user = new User("Jerry"); console.log('Avant [console.log(user.idName)]'); console.log(user.idName,"- direct"); // Jerry console.log('Avant user=new User("")'); user = new User("Jerry"); // idName trop court. console.log('The END!'); </script> Ex Exécution-trac cution-trac cution-tracée, e, avec YANDEX YANDEX: : 00:08:22.781 test.html:23 Avant let user=new User("John") 00:08:22.784 test.html:4 Ds constructor. 00:08:22.784 test.html:14 Ds setter. 00:08:22.785 test.html:25 Avant [console.log(user.idName)] 00:08:22.785 test.html:9 Jerry - de get 00:08:22.785 test.html:26 Jerry - direct 00:08:22.786 test.html:28 Avant user=new User("") 00:08:22.786 test.html:4 Ds constructor. 00:08:22.786 test.html:14 Ds setter. J.D.B. DIASOLUKA Nz. Luyalu 9 / 16 JavaScript Tome-III 00:08:22.787 test.html:30 The END! « symbole.species » permet de surcharger le constructeur par défaut d’une méthode qui renvoie un objet Array avec une sousclasse par exemple MonArray e.g. la méthode map() , par exemple pour modifier le format <du résultat. <script type="text/javascript"> "use strict"; class MonArray extends Array { static get [Symbol.species]() { return Object; } // On surcharge species avec le constructeur Object } var a = new MonArray("2","4","6"); console.log(a instanceof MonArray); // true var mapped = a.map(x => x * x); console.log(mapped); // Number {3, 0: 4, 1: 16, 2: 36} console.log(MonArray); // class MonArray extends Array {} console.log(mapped console.log(mapped console.log(mapped console.log(mapped instanceof instanceof instanceof instanceof MonArray); Array); Object); Number); // // // // false false true true console.log("=========="); class MonArray2 extends Array { static get [Symbol.species]() { return Array; } // On surcharge species avec le constructeur Array } var a = new MonArray2("2","4","6"); var mapped = a.map(x => x * x); console.log(mapped);// Array [ 4, 16, 36 ] console.log(MonArray); // class MonArray extends Array {} console.log(mapped instanceof MonArray2); // false console.log(mapped instanceof Array); // true console.log(mapped instanceof Object); // true console.log(mapped instanceof Number); // false </script> Ne confondez pas la méthode Array.map (qui permet d’appliquer un même traitement à chaque membre d’une array) et l’objet Map (capitalisé) qui permet de créer un objet HashTable ou Dictionary. Ce HashTable est comme un objet ordinaire avec des clés et des valeurs associées, sauf qu’un Map peut utiliser comme clé n’importe J.D.B. DIASOLUKA Nz. Luyalu 10 / 16 JavaScript Tome-III quoi sauf les mots clés (numérique, string ou objet), alors que les autres objets n’admettent que des strings comme clés. Pour accéder aux clés Map utilise les méthodes « get » et « set »., alors que les objets utilisent le point séparateur (objet.clé). La clé d’un Map doit être soit un nombre (entre guillemets ou pas : les deux sont distincts), soit une chaîne représenté un objet déjà défini, ou alors une chaîne littérale (entre guillemets). <script type="text/javascript"> "use strict"; let y = new Map(); // objet Map y.set(2018, 'val de 2018'); y.set("25", 'val de 25'); y.set("z", 'val de "z"'); let x = new Map(); // objet Map let objectKey = { key: 'keyvalue' }; // litt d'objet. console.log(objectKey); // Object { key: "keyvalue" } console.log(objectKey.key); // keyvalue console.log(x.get(objectKey)); // undefined x.set(1, 'clé numérique'); console.log(x.get(1)); // clé numérique x.set('1', 'clé string'); console.log(x.get('1')); // clé string x.set('objk', objectKey); console.log(x.get('objk')); // Object { key: "keyvalue" } x.set(objectKey, ['une', 'Array', 'comme', 'valeur']); console.log(x.get(objectKey)); // (4) ["une", "Array", "comme", "valeur"] console.log(objectKey.key); // keyvalue let fv=function(){this.pr="Property"}; x.set(fv, 'objet expression de fonction'); console.log(x.get(fv)); // objet expression de fonction console.log(y); J.D.B. DIASOLUKA Nz. Luyalu 11 / 16 JavaScript Tome-III // Map(3) {2018 => "val de 2018", "25" => "val de 25", "z" => "val de "z""} x.set(y, 'Et même un autre objet Map'); console.log(x.get(y)); // Et même un autre objet Map // L'objet Map clé ici n'altère pas // l'objet Map de départ. console.log(y); // Map(3) {2018 => "val de 2018", "25" => "val de 25", "z" => "val de "z""} // L'objet Map de départ n'a pas été altéré. console.log(x); // Map(6) {1 => "clé numérique", "1" => "clé string", "objk" => {…}, {…} => Array(4), ƒ => "objet expression de fonction", …} </script> Création d’objet Map avec des itérables (array d’arrays ou un générateur) : new Map ( iterable : Object ). <script type="text/javascript"> "use strict"; var obj_key = { prop: 'property' }; var fromArray = new Map( [[0, 'array0'], [obj_key, 'array1']]); // Initialisation de fromArray // (nouvel objet Map) // avec une itération d'arrays. console.log(fromArray.get(0)); // array0 console.log(fromArray.get(obj_key)); // array1 console.log(); // Gnération d'entrées de Map // avec une fonction génératrice. var generator_fct = function*() { yield [15, 'g15']; yield [obj_key, 'gObK']; }; // Initialisation de fromGenerator // (nouvel objet Map) // avec les entrées générées par un générateur. J.D.B. DIASOLUKA Nz. Luyalu 12 / 16 JavaScript Tome-III var fromGenerator = new Map(generator_fct()); // Affichage des entrées de fromGenerator. console.log(fromGenerator.get(15)); // g15 console.log(fromGenerator.get(obj_key)); // gObK console.log(fromGenerator.size); // 2 fromGenerator.set('add', 'value of add'); console.log(fromGenerator.size); // 3 fromGenerator.delete(15); // Retire console.log(fromGenerator); // Map(2) {{…} => "gObK", "add" => "value of add"} fromGenerator.clear(); // Efface tout console.log(fromGenerator); // Map { } </script> Parcourons quelques propriétés de Map : fromGenerator.hasOwnProperty() : false fromGenerator.valueOf() : Map { 15 -> "g15", {…} -> "gObK" } fromGenerator.toString() : [object Map]" fromGenerator.toSource() : "({})" fromGenerator.size : 2 fromArray.has(0) : true fromGenerator.has(15) : true fromGenerator.has(150) : false Le prototype de Map : Map() length: 0 name: "Map" prototype: {…} clear: function clear() constructor: function Map() delete: function delete() entries: function entries() forEach: function forEach() get: function get() has: function has() keys: function keys() set: function set() J.D.B. DIASOLUKA Nz. Luyalu 13 / 16 JavaScript Tome-III size: Getter values: function values() Symbol(Symbol.iterator): undefined Symbol(Symbol.toStringTag): undefined __proto__: Object { … } Symbol(Symbol.species): undefined __proto__: function () Map.entries() : <script type="text/javascript"> "use strict"; var iMap = new Map( [ [1, 'valueof 1'], ['s', 'valueof s'], ['9', 'valueof 9'] ]); // BOUCLE FOR(...OF...) : Les entrées sont // returnées par iMap[Symbol.iterator] for (var value of iMap) { console.log(value); } // Array [ 1, "valueof 1" ] // Array [ "s", "valueof s" ] // Array [ "9", "valueof 9" ] // ITÉRATION EXPLICITE à travers les entrées for (var value of iMap.values()) { console.log(value); } // valueof 1 // valueof s // valueof 9 for (var entry of iMap.entries()) { console.log(entry); } // Array [ 1, "valueof 1" ] // Array [ "s", "valueof s" ] // Array [ "9", "valueof 9" ] // PARCOURS MANUEL DE L'ITÉRATEUR var entries = iMap.entries(); console.dir(entries.next()); console.dir(entries.next()); console.dir(entries.next()); console.dir(entries.next()); /* J.D.B. DIASOLUKA Nz. Luyalu 14 / 16 JavaScript Tome-III Object done: false value: (2) [1, "valueof 1"] Object done: false value: (2) ["s", "valueof s" Object done: false value: (2) ["9", "valueof 9"] Object done: true value: undefined */ // ITÉRATION AVEC FOREACH iMap.forEach(function(val, cle, obj) { console.log( 'clé: "' + cle + '", val: "' '+obj); }); // clé: "1", val: "valueof 1" [object // clé: "s", val: "valueof s" [object // clé: "9", val: "valueof 9" [object + val + '" Map] Map] Map] // FOR (...OF...) pour parcourir l'itérateur for(var cle of iMap.keys()) { console.log(cle); } // 1 // s // 9 for(var val of iMap.values()) { console.log(val); } // valueof 1 // valueof s // valueof 9 // UN AUTRE ACCÈS MANUEL À L'ITÉRATEUR var cles = iMap.keys(); console.log(cles.next()); console.log(cles.next()); console.log(cles.next()); console.log(cles.next()); // Object { value: 1, done: false } // Object { value: "s", done: false } // Object { value: "9", done: false } // Object { value: undefined, done: true } var vals = iMap.values(); J.D.B. DIASOLUKA Nz. Luyalu 15 / 16 JavaScript Tome-III console.log(vals.next()); console.log(vals.next()); console.log(vals.next()); console.log(vals.next()); // Object { value: "valueof 1", done: false } // Object { value: "valueof s", done: false } // Object { value: "valueof 9", done: false } // Object { value: undefined, done: true } </script> III. Remplacer des membres d’Array par d’autres : <script type = "text/javascript"> "use strict"; // Remplacez tous les "Louis" par "Rose" et "Blue". function suppress(parr, val) { var i; while ((i = parr.indexOf(val)) != -1) { parr.splice(i, 1,"*ROSE*","*MAGENTA*"); } return parr; } let arr=["Louis", "Delon", "Keriy", "Louis"] let narr=suppress(arr, "Louis") console.log(narr); /* FIREFOX & MAXTHON : Array [ "*ROSE*", "*MAGENTA*", "Delon", "Keriy", "*ROSE*", "*MAGENTA*" ] OPERA : (6) ["*ROSE*", "*MAGENTA*", "Delon", "Keriy", "*ROSE*", "*MAGENTA*"] YANDEX : 1. Array(6) A 0:"*ROSE*" B 1:"*MAGENTA*" C 2:"Delon" D 3:"Keriy" E 4:"*ROSE*" F 5:"*MAGENTA*" */ </script> J.D.B. DIASOLUKA Nz. Luyalu 16 / 16 JavaScript Tome-III