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!

0
tau 7 oct. 2011 à 04:45

3 réponses

Meilleure réponse

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.

2
Matt Ball 7 oct. 2011 à 00:51

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;
};
1
Community 23 mai 2017 à 12:19

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"

//...
6
CMS 7 oct. 2011 à 05:01
7682034