Voici un exemple:
var Box = function() {
this.id = generateUniqueId();
};
Box.prototype = {
add:function(parent) {
parent.appendChild(this.elm);
}
};
var NewBox = function() {
this.newThing = true;
};
NewBox.prototype = new Box();
NewBox.prototype.remove = function() {
this.elm.parentNode.removeChild(this.elm);
};
var a = new NewBox();
var b = new NewBox();
alert(a.id); // alerts 0
alert(b.id); // also alerts 0! :@
Je voudrais avoir a et b (essentiellement chaque fois que je crée un NewBox
) avoir leur propre id
. Je comprends que NewBox
utilise l'héritage prototypique et hérite donc d'une seule instance du id
généré qu'il obtient de Box
, mais je voudrais que chaque {{X5} } obtient son propre id
sans avoir à le dire explicitement à l'intérieur du constructeur NewBox
.
C'est peut-être impossible ou je fais quelque chose de vraiment mal, alors aidez-moi!
Merci beaucoup!
3 réponses
C'est peut-être impossible ou je fais quelque chose de vraiment mal, alors aidez-moi!
Vous faites quelque chose de mal.
Si vous voulez des valeurs spécifiques à l'instance, initialisez-les dans le constructeur, pas dans le prototype.
Matt Ball a la bonne idée. Essayez plutôt:
var Box = (function(){
var numberOfBoxes = 0;
function() {
this.id = numberOfBoxes++;
}
})();
Ou dans le cas où vous souhaitez que toutes vos (différentes) classes aient des identifiants uniques:
var generateUniqueID = (function(){
var runningCount = 0;
return function (){
return runningCount++;
}
})();
var Box = function() {
this.id = generateUniqueId();
};
var NewBox = function() {
this.id = generateUniqueId();
this.newThing = true;
};
Dans votre exemple, le constructeur Box
n'est exécuté que lorsque vous définissez l'objet NewBox.prototype
.
Vous pouvez contourner ce problème en appelant la fonction constructeur Box
à l'intérieur NewBox
avec le méthode Function.prototype.apply
, pour définir la valeur this
et transmettre toutes les valeurs d'argument, par exemple:
//..
var NewBox = function() {
Box.apply(this, arguments);
this.newThing = true;
};
//..
var a = new NewBox();
var b = new NewBox();
// assuming your `generateUniqueId` function
// increments a number
alert(a.id); // will alert 1
alert(b.id); // will alert 2
Maintenant, chaque fois que le constructeur NewBox
est appelé pour créer une nouvelle instance d'objet (new NewBox();
), il appellera la fonction Box
pour lui appliquer toute sa logique. Cela vous aidera à éviter de répéter la logique du constructeur parent encore et encore.
Le apply
, est utilisé appelez la fonction constructeur "parent" en définissant la valeur this
à l'instance d'objet qui est créée par le constructeur NewBox
et nous passons tous les arguments fournis à cette fonction.
Votre exemple montre également un problème courant, lorsque vous exprimez une relation d'héritage via NewBox.prototype = new Box();
le constructeur Box
est appelé et qu'il a des effets secondaires, ce nouvel objet sera initialisé et votre fonction generateUniqueId
sera exécuté pour la première fois, si vous voulez éviter cela, vous devez soit utiliser un constructeur temporaire, juste pour créer un nouvel objet qui hérite de Box.prototype
, soit utiliser la nouvelle méthode ECMAScript 5 Object.create
pour le même objectif, par exemple:
function inherit(o) {
function Tmp() {}
Tmp.prototype = o;
return new Tmp();
}
//.....
NewBox.prototype = inherit(Box.prototype);
Ou:
NewBox.prototype = Object.create(Box.prototype);
De cette façon, vous exprimez la même hiérarchie d'héritage sans exécuter votre constructeur Box
la première fois, en évitant tout effet secondaire qu'il pourrait provoquer.
Enfin et surtout, chaque fois que vous remplacez la propriété prototype d'une fonction, il est toujours recommandé de restaurer la propriété constructor
de ce nouvel objet prototype, sinon elle pointera vers la mauvaise fonction.
Dans votre exemple, puisque vous remplacez le NewBox.prototype
par une nouvelle instance de Box
, la propriété NewBox.prototype.constructor
pointera sur Box
(vos instances sont affectées, par exemple {{X4) }}) au lieu de NewBox
comme vous vous en doutez, nous devons le reculer, par exemple:
NewBox.prototype = someObject; // as any of the examples above
NewBox.prototype.constructor = NewBox;
Vous pouvez résumer ces détails dans une fonction, comme je l'ai fait dans la fonction inherit
ci-dessus:
function inherits(child, parent) {
var obj, Tmp = function () {};
Tmp.prototype = parent.prototype;
obj = new Tmp();
child.prototype = obj;
child.prototype.constructor = child;
}
//...
// instead of setting the `NewBox.prototype` manually
inherits(NewBox, Box); // "NewBox inherits from Box"
//...
Questions connexes
De nouvelles questions
javascript
Pour des questions concernant la programmation dans ECMAScript (JavaScript / JS) et ses divers dialectes / implémentations (hors ActionScript). Veuillez inclure toutes les balises pertinentes dans votre question; par exemple, [node.js], [jquery], [json], etc.