Question

I'been faire un peu d'héritage dans js afin de mieux le comprendre, et je l'ai trouvé quelque chose qui me confond.

Je sais que lorsque vous appelez une « fonction constructeur » avec le nouveau mot clé, vous obtenez un nouvel objet avec une référence au prototype de cette fonction.

Je sais aussi que pour faire l'héritage prototypal vous devez remplacer le prototype de la fonction constructeur avec une instance de l'objet que vous voulez être la « superclasse ».

Je l'ai fait cet exemple ridicule d'essayer ces concepts:

function Animal(){}
function Dog(){}

Animal.prototype.run = function(){alert("running...")};

Dog.prototype = new Animal(); 
Dog.prototype.bark = function(){alert("arf!")};

var fido = new Dog();
fido.bark() //ok
fido.run() //ok

console.log(Dog.prototype) // its an 'Object' 
console.log(fido.prototype) // UNDEFINED
console.log(fido.constructor.prototype == Dog.prototype) //this is true

function KillerDog(){};
KillerDog.prototype.deathBite = function(){alert("AAARFFF! *bite*")}

fido.prototype = new KillerDog();

console.log(fido.prototype) // no longer UNDEFINED
fido.deathBite(); // but this doesn't work!

(Cela a été fait dans la console de Firebug)

1) Pourquoi si tous les nouveaux objets contiennent une référence au prototype de la fonction de créateur, fido.prototype est indéfini?

2) est la chaîne d'héritage [obj] -> [constructeur] -> [prototype] au lieu de [obj] -> [prototype]

3) est la propriété 'prototype' de notre objet (fido) jamais vérifié? si oui ... pourquoi est « deathBite » non définie (dans la dernière partie)?

Était-ce utile?

La solution

  

1) Pourquoi si tous les nouveaux objets contiennent une   référence à la fonction de créateur   prototype, fido.prototype est   non définie?

Tous les nouveaux objets ne détiennent une référence au prototype qui était présent sur leur constructeur au moment de la construction. Toutefois, le nom de la propriété utilisée pour stocker cette référence n'est pas prototype car il est sur la fonction constructeur lui-même. Certaines implémentations Javascript autorisent l'accès à cette propriété « cachée » via un nom de propriété comme __proto__ où d'autres ne le font pas (par exemple Microsofts).

  

2) est la chaîne d'héritage [obj] ->   [Constructeur] -> [prototype] au lieu   de [obj] -> [prototype]

Non. Jetez un oeil à ceci: -

function Base() {}
Base.prototype.doThis = function() { alert("First"); }

function Base2() {}
Base2.prototype.doThis = function() { alert("Second"); }

function Derived() {}
Derived.prototype = new Base()

var x = new Derived()

Derived.prototype = new Base2()

x.doThis();

Cette alerte ne deuxième "First". Si la chaîne d'héritage est allé par le constructeur, nous verrions « Second ». Quand un objet est construit de la référence de courant a eu lieu dans les fonctions propriété prototype est transférée à l'objet de référence caché à son prototype.

  

3) est la propriété 'prototype' de notre   objet (fido) jamais vérifié? si c'est le cas...   pourquoi est indéfini « deathBite » (dans le   dernière partie)?

Affectation à un objet (autre qu'une fonction) une propriété appelée prototype n'a pas de signification particulière, comme indiqué précédemment un objet ne maintient pas une référence à son prototype par un tel nom de la propriété.

Autres conseils

Vous ne pouvez pas changer une fois qu'il a été instancié avec new prototype d'un objet.

Dans votre exemple ci-dessus, des lignes comme

fido.prototype = new KillerDog();

crée simplement un nouvel attribut nommé prototype sur le fido objet, et définit cet attribut à un nouvel objet KillerDog. Il est pas différent de

fido.foo = new KillerDog();

votre code signifie ...

// Doesn't work because objects can't be changed via their constructors
fido.deathBite();

// Does work, because objects can be changed dynamically, 
// and Javascript won't complain when you use prototype 
//as an object attribute name
fido.prototype.deathBite();

Le comportement prototype spécial applique uniquement aux constructeurs en javascript, où les constructeurs sont functions qui seront appelés à new.

Réponse par des chiffres à vos questions:

  1. la propriété prototype de l'objet n'est pas appelé prototype. La norme utilise [[prototype]] pour le désigner. Firefox rend ce propriété public sous le nom de __proto __.
  2. La chaîne d'héritage est [obj][prototype object]. Votre hypothèse originale ([obj][constructor] ⇒ de [prototype]) est incorrect et vous pouvez facilement réfuter en modifiant constructor et / ou constructor.prototype, et vérifier quelles méthodes peuvent être appelées sur votre [obj] - vous découvrirez que ces modifications ne changent rien
  3. propriété prototype sur les objets ne sont pas vérifiées et non utilisés. Vous pouvez définir à ce que vous voulez. JavaScript utilise la fonction des objets que lors de la construction de l'objet.

Pour démontrer la # 3 est ici le code de Dojo :

dojo.delegate = dojo._delegate = (function(){
  // boodman/crockford delegation w/ cornford optimization
  function TMP(){}
  return function(obj, props){
    TMP.prototype = obj;
    var tmp = new TMP();
    if(props){
      dojo._mixin(tmp, props);
    }
    return tmp; // Object
  }
})();

Comme vous pouvez le voir profite du fait que prototype est utilisé que dans un seul endroit en réutilisant la même fonction TMP pour tous les objets délégués avec différents prototypes. En fait prototype est affecté directement avant d'appeler la fonction avec new, et il sera changé après n'affectant tous les objets créés.

Vous pouvez trouver l'objet séquence créée dans ma réponse à Relation entre [[prototype]] et prototype en JavaScript .

Je sais que ça a déjà été répondu, mais il y a une meilleure façon de faire de l'héritage. Appeler un constructeur uniquement dans le but de l'héritage n'est pas souhaitable. L'un des effets indésirables est.

function Base() {this.a = "A"}
function Child() {this.b = "B"};

Child.prototype = new Base();

Vous avez ajouté la propriété « a » au prototype de l'enfant que vous ne l'avez pas l'intention.

Voici la bonne façon (je ne l'ai pas inventé cela, Ext-JS et d'autres libs utilisent ce)

// This is used to avoid calling a base class's constructor just to setup inheritance.
function SurrogateCtor() {}

/**
 * Sets a contructor to inherit from another constructor
 */
function extend(BaseCtor, DerivedCtor) {
  // Copy the prototype to the surrogate constructor
  SurrogateCtor.prototype = BaseCtor.prototype;
  // this sets up the inheritance chain
  DerivedCtor.prototype = new SurrogateCtor();
  // Fix the constructor property, otherwise it would point to the BaseCtor
  DerivedCtor.prototype.constructor = DerivedCtor;
  // Might as well add a property to the constructor to 
  // allow for simpler calling of base class's method
  DerivedCtor.superclass = BaseCtor;
}

function Base() {
  this.a = "A";
}

Base.prototype.getA = function() {return this.a}

function Derived() {
  Derived.superclass.call(this);  // No need to reference the base class by name
  this.b = "B";
}

extend(Base, Derived);
// Have to set methods on the prototype after the call to extend
// otherwise the prototype is overridden;
Derived.prototype.getB = function(){return this.b};
var obj = new Derived();

Encore plus simple est d'ajouter un troisième paramètre à étendre où vous spécifiez la méthode de la classe dérivée de sorte que vous ne devez pas appeler étendre puis ajouter des méthodes au prototype

extend(BaseCtor, DerivedCtor, {
  getB: function() {return this.b}
});

Ensuite, il y a beaucoup d'autres choses que vous pouvez faire pour le sucre syntaxique.

blogué sur ce: http: // js -bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

A noter que dans ECMAScript 5 (la dernière version du langage JavaScript), vous pouvez accéder à la propriété interne [[Prototype]] d'une instance via Object.getPrototypeOf :

Object.getPrototypeOf(fido) === Dog.prototype
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top