Des constructeurs plus flexibles

Des constructeurs plus flexibles

Les fonctions constructeur vues jusqu'à présent ne vous permettent pas de spécifier les valeurs des propriétés lorsque vous créez une instance. Comme dans Java, vous pouvez fournir des arguments aux constructeurs pour initialiser les valeurs des propriétés des instances. La figure suivante montre une façon de le faire.

 


Figure 8.5: Initialiser les propriétés dans un constructeur, 1° étape

La table suivante montre les définitions de ces objets en Java et Javascripts.

JavaScript Java
function Employé (nom, dep) {
  this.nom = nom || "";
  this.département = dep || "général";
}
public class Employé {
   public String nom;
   public String département;
   public Employé () {
this("", "général"); } public Employé (String nom) {
this(nom, "général"); } public Employé (String nom, String dep) {
this.nom = nom;
this.département = dep; } }
function Collaborateur (projs) {
  this.projets = projs || [];
}
Collaborateur.prototype = new Employé;
import java.util.List;
import java.util.ArrayList;

public class Collaborateur extends Employé {
public List<String> projets; public Collaborateur () {
this(new ArrayList<String>()); } public Collaborateur (List<String> projs) {
projets = projs; } }
 
function Ingénieur (mach) {
   this.département = "développement";
   this.machine = mach || "";
}
Ingénieur.prototype = new Collaborateur;
public class Ingénieur extends Collaborateur {
public String machine; public Ingénieur () {
département = "développement";
machine = ""; } public Ingénieur (String mach) {
département = "développement";
machine = mach; } }


Ces définitions en JavaScripts utilisent une syntaxe spéciale pour assigner les valeurs par défaut :

this.nom = nom || "";

L'opérateur logique OU de JavaScript (||) évalue le premier argument. Si cet argument est résolu comme 'vrai', c'est lui que l'opérateur retourne. Sinon, l'opérateur retourne la valeur du second argument. Donc, cette ligne de code teste si nom a une valeur appropriée pour la propriété nom. Si c'est le cas, elle assigne à this.nom cette valeur. Sinon, elle assigne à this.nom la chaîne de caractères vide. Nous utilisons cette syntaxe pour sa concision; cependant, elle peut être déroutante au premier abord. Nota bene: Des résultats inattendus peuvent survenir avec les arguments numériques ou booléens, car les valeurs 0 (zéro) et faux entraineront le choix de la valeur par défaut; pour ces cas vous devrez utiliser la syntaxe suivante encore plus absconse, mais qui donne le comportement voulu pour tous les types de données :

this.autorisé = typeof(autor) !== 'undefined' ? autor : true;

Avec ces définitions, quand vous créez une instance d'un objet, vous pouvez spécifier des valeurs pour les propriétés définies localement. Comme on le voit dans la Figure 8.5, vous pouvez utiliser l'instruction suivante pour créer un nouvel Ingénieur:

jane = new Ingénieur("belau");

Les propriétés de Jane sont alors :

jane.nom == "";
jane.département == "développement";
jane.projets == [];
jane.machine == "belau"

Mais notez qu'avec ces définitions, vous ne pouvez pas spécifier de valeurs initiales pour une propriété héritée comme nom. En JavaScripts, si vous voulez spécifier une valeur initiale pour des propriétés héritées, vous devez ajouter du code à la fonction contructeur.

Jusqu'ici, la fonction constructeur créait un objet générique et spécifiait ensuite des propriétés locales et des valeurs pour le nouvel objet. Vous pouvez enrichir le constructeur en appelant directement la fonction constructeur d'un objet plus élevé dans la hiérarchie des prototypes. La figure suivante montre ces nouvelles définitions.


Figure 8.6 Initialiser les propriétés dans un constructeur, 2° étape

Examinons en détail une de ces définitions. Voici la nouvelle définition du constructeur Ingénieur:

function Ingénieur (nom, projs, mach) {
  this.base = Collaborateur;
  this.base(nom, "développement", projs);
  this.machine = mach || "";
}

Supposons que vous créiez un nouvel objet Ingénieur comme ceci:

jane = new Ingénieur("Doe, Jane", ["navigator", "javascript"], "belau");

JavaScript suit ces étapes:

  1. L'opérateur new crée un objet générique et assigne sa propriété __proto__ comme Ingénieur.prototype.
  2. L'opérateur new transmet le nouvel objet au constructeur Ingénieur comme valeur du mot clé this.
  3. Le constructeur crée pour cet objet une nouvelle propriété nommée base et assigne à la propriété base la valeur du constructeur Collaborateur. En sorte que le constructeur Collaborateur devient une méthode de l'objet Ingénieur. Le nom de la propriété base n'est pas spécial. Vous pouvez utiliser n'importe quel nom légal de propriété; base est simplement signifiant pour l'utilisation qui en est faite.
  4. Le constructeur appelle la méthode base, en lui passant comme arguments deux des arguments passés au constructeur ("Doe, Jane" et ["navigator", "javascript"]) ainsi que la chaîne de caractères "développement". En utilisant explicitement "développement" dans le constructueur, on spécifie que tous les objets Ingénieur ont la même valeur pour la propriété héritée département, et cette valeur surcharge la valeur héritée de Employé.
  5. Comme base est une méthode de Ingénieur, par l'appel à base, JavaScript lie le mot-clé this à l'objet créé dans l'Étape 1. Donc, la fonction Collaborateur passe à son tour les arguments "Doe, Jane" et ["navigator", "javascript"] à la fonction constructeur Employé. Au retour de la fonction constructeur Employé, la fonction Collaborateur utilise l'argument restant pour assigner la propriété projets.
  6. Au retour de la méthode base, le constructeur Ingénieur initialise la propriété machine de l'objet à "belau".
  7. Au retour du constructeur, JavaScript assigne le nouvel objet à la variable jane.

Vous pensez peut-être que, en ayant appelé le constructeur Collaborateur de l'intérieur du Ingénieur, vous avez mis en place l'héritage approprié pour les objets Ingénieur. Ce n'est pas le cas. L'appel au Collaborateur assure qu'un objet Ingénieur soit initialisé avec les propriétés spécifiées dans toutes les fonctions appelées depuis le constructeur. Cependant, si vous ajoutez ultérieurement des propriétés aux prototypes Employé ou Collaborateur, ces propriétés ne seront pas héritées par l'objet Ingénieur. Par exemple, supposons que vous ayiez l'instruction suivante :

function Ingénieur (nom, projs, mach) {
  this.base = Collaborateur;
  this.base(nom, "développement", projs);
  this.machine = mach || "";
}
jane = new Ingénieur("Doe, Jane", ["navigator", "javascript"], "belau");
Employé.prototype.spécialité = "none";

L'objet jane n'héritera pas la propriété spécialité. Vous devez encore initialiser explicitement le prototype pour assurer l'héritage dynamique. Supposons que vous ayiez au contraire ces instructions :

function Ingénieur (nom, projs, mach) {
this.base = Collaborateur;
this.base(nom, "développement", projs);
this.machine = mach || ""; } Ingénieur.prototype = new Collaborateur;
jane = new Ingénieur("Doe, Jane", ["navigator", "javascript"], "belau");
Employé.prototype. spécialité = "none";

Maintenant la valeur de la propriété spécialité de l'objet jane est "none".

<hr>

Une autre façon d'hériter est d'utiliser les méthodes .call/.apply. Les instructions ci-dessous sont équivalentes:

function Ingénieur (nom, projs, mach) {
  this.base = Collaborateur;
this.base(nom, "développement", projs);
this.machine = mach || ""; }
function Ingénieur (nom, projs, mach) {
Collaborateur.call(this, nom, "développement", projs);
this.machine = mach || ""; }

L'utilisation de la méthode .call de JavaScript est une implémentation plus propre puisque ".base" n'est plus nécessaire.

Pièces jointes

Fichier Taille Date Joint par
hier05.gif
25929 octets 2009-09-21 18:57:25 xmartin
hier06.gif
27863 octets 2009-09-21 18:57:27 xmartin
Cursor 'text'
Cursor 'text'
86 octets 2012-08-02 03:49:21 teoli
Cursor 'text'
Cursor 'text
86 octets 2012-08-02 03:52:12 teoli

Étiquettes et contributeurs liés au document

Contributeurs ayant participé à cette page : xmartin
Dernière mise à jour par : xmartin,