Pregunta

I'been haciendo un poco de herencia en js con el fin de comprenderlo mejor, y me encontré con algo que me confunde.

Sé que cuando se llama a un 'función constructora' con la nueva palabra clave, se obtiene un nuevo objeto con una referencia al prototipo de esa función.

también sé que con el fin de hacer herencia de prototipos debe reemplazar el prototipo de la función constructora con una instancia del objeto que desea ser el 'superclase'.

Así que hice este ejemplo tonto para tratar estos conceptos:

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!

(Esto se hizo en la consola de Firebug)

1) ¿Por qué si todos los nuevos objetos contienen una referencia al prototipo de la función de creador, fido.prototype es indefinido?

2) es la cadena de herencia [obj] -> [constructor] -> [Prototype] en lugar de [obj] -> [Prototype]

3) es la propiedad 'prototipo' de nuestro objeto (Fido) cada vez verificado? Si es así ... ¿por qué es 'deathBite' no definido (en la última parte)?

¿Fue útil?

Solución

  

1) ¿Por qué si todos los nuevos objetos contienen una   referencia a la función de creador   prototipo, es fido.prototype   indefinido?

Todos los nuevos objetos estén en posesión de una referencia al prototipo que estuvo presente en su constructor en el momento de la construcción. Sin embargo, el nombre de la propiedad se utiliza para almacenar esta referencia no se prototype como lo es en la propia función constructora. Algunas implementaciones JavaScript Es importante permitir el acceso a esta propiedad 'oculta' a través de algún nombre de la propiedad como __proto__ donde otros no lo hacen (por ejemplo Microsoft de).

  

2) es la cadena de herencia [obj] ->   [Constructor] -> [prototipo] en lugar   de [obj] -> [Prototype]

No. Echar un vistazo a esto: -

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();

Esto alerta "primero" no segundo. Si la cadena de herencia pasó a través del constructor veríamos "Segundo". Cuando se construye un objeto de la referencia de corriente que tuvo lugar en la propiedad Funciones prototipo se transfiere al objeto de referencia oculta a su prototipo.

  

3) es la propiedad 'prototipo' de nuestra   objeto (Fido) cada vez verificado? si es así...   ¿por qué es 'deathBite' no definido (en el   última parte)?

Asignar a un objeto (que no sea una función) una propiedad llamada prototype tiene ningún significado especial, como se dijo anteriormente un objeto no mantiene una referencia a su prototipo a través de un nombre de dicha propiedad.

Otros consejos

No se puede cambiar el prototipo de un objeto, una vez ha sido instanciado con new.

En el ejemplo anterior, como líneas

fido.prototype = new KillerDog();

simplemente crea un nuevo atributo llamado prototype en el fido objeto, y establece que el atributo a un nuevo objeto KillerDog. No es diferente que

fido.foo = new KillerDog();

A medida que su código se encuentra ...

// 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();

El comportamiento especial prototype se aplica sólo a los constructores en JavaScript, donde los constructores están functions que serán llamados con new.

respuesta por números a sus preguntas:

  1. propiedad prototype del objeto no se llama prototype. El estándar utiliza [[prototype]] para designarlo. Firefox hace que esta propiedad pública bajo el nombre de __proto __.
  2. La cadena de herencia es [obj][prototype object]. Su hipótesis inicial ([obj][constructor][prototype]) es incorrecta y se puede refutar fácilmente modificando constructor y / o constructor.prototype, y comprobar qué métodos pueden ser llamados en su [obj] - usted descubrirá que estas modificaciones no cambian nada
  3. prototype propiedad sobre los objetos no son controlados y no se utiliza. Usted puede configurarlo para lo que quiera. JavaScript utiliza en los objetos junto función sólo durante la construcción de objetos.

Para demostrar el # 3 aquí está el código 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
  }
})();

Como se puede ver que se aprovecha del hecho de que prototype se utiliza sólo en un lugar mediante la reutilización de la misma TMP función para todos los objetos delegados con diferentes prototipos. De hecho prototype se asigna directamente antes de invocar la función con new, y se cambió después de que no afecte a los objetos creados.

Puede encontrar la secuencia creada objeto en mi respuesta a [[Prototype]] y el prototipo en JavaScript .

Sé que ya ha sido contestada, pero, hay una mejor manera de hacerlo herencia. Llamar a un constructor sólo con el propósito de herencia no es deseable. Uno de los efectos no deseados es.

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

Child.prototype = new Base();

Ahora propiedad Ha añadido "a" para el prototipo de niño que no tenía intención de.

Esta es la manera correcta (Yo no inventé esto, Ext-JS y otras librerías utilizan este)

// 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();

Una forma aún más fácil es agregar un tercer parámetro para extender donde se especifica el método de la clase derivada de modo que usted no tiene que llamar a extender y luego añadir métodos al prototipo

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

A continuación, hay muchas otras cosas que podría hacer para el azúcar sintáctica.

escribió en su blog sobre él: http: // JS -bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

A tener en cuenta que, en ECMAScript 5 (es decir, la última versión del lenguaje JavaScript) se puede obtener acceso a la interna [[Prototype]] propiedad de una instancia a través de Object.getPrototypeOf :

Object.getPrototypeOf(fido) === Dog.prototype
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top