2009-05-21 17 views
162

Soy nuevo en JavaScript OOP. ¿Puedes explicar la diferencia entre los siguientes bloques de código? Probé y ambos bloques funcionan. ¿Cuál es la mejor práctica y por qué?Comprender herencia prototípica en JavaScript

Primer bloque:

function Car(name){ 
    this.Name = name; 
} 

Car.prototype.Drive = function(){ 
    document.write("My name is " + this.Name + " and I'm driving. <br />"); 
} 

SuperCar.prototype = new Car(); 
SuperCar.prototype.constructor = SuperCar; 

function SuperCar(name){ 
    Car.call(this, name); 
} 

SuperCar.prototype.Fly = function(){ 
    document.write("My name is " + this.Name + " and I'm flying! <br />"); 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

Segundo bloque:

function Car(name){ 
    this.Name = name; 
    this.Drive = function(){ 
     document.write("My name is " + this.Name + " and I'm driving. <br />"); 
    } 
} 

SuperCar.prototype = new Car(); 

function SuperCar(name){ 
    Car.call(this, name); 
    this.Fly = function(){ 
     document.write("My name is " + this.Name + " and I'm flying! <br />"); 
    } 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

¿Por qué el autor añade Drive y Fly métodos usando prototype, pero no se le declara como this.Drive método dentro de la clase y Carthis.Fly en SuperCar clase?

¿Por qué SuperCar.prototype.constructor debe volver a establecerse en SuperCar? ¿La propiedad del constructor se reemplaza cuando se establece prototype? Comenté esta línea y nada cambió.

¿Por qué llamar al Car.call(this, name); en el constructor SuperCar? No van a propiedades y métodos de Car ser 'heredados' cuando lo haga

var myCar = new Car("Car"); 
+3

La forma más moderna es el uso de Object.create () en lugar de nuevo: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

+2

Solo una nota, este ejemplo puede ser confuso: 'super' en este caso se refiere a un auto volador, mientras que 'super' en OOP normalmente se refiere al prototipo/clase principal. – mikemaccana

+2

Creo que la parte que hace que la herencia prototípica de JavaScript sea difícil de entender es cuando se mezcla con un constructor. Qué pasa si eliminamos la idea del constructor y la clase, y solo tenemos objetos. Cada objeto se hereda de nada (nulo) o de otro objeto. Eso será mucho más fácil de entender, y es precisamente lo que Object.create() hace. –

Respuesta

78

Los dos bloques se diferencian de una manera que en el primer ejemplo Drive() sólo existirá una vez, mientras que en el segundo enfoque Drive() existirá por instancia (Cada vez que haces new Car() la función drive() se creará de nuevo). O diferente dijo que el primero usa el prototipo para almacenar la función y el segundo el constructor. La búsqueda de funciones es constructor y luego prototipo. Por lo tanto, para su búsqueda de Drive() lo encuentra independientemente de si está en el constructor o en el prototipo. Usar el prototipo es más eficiente porque usualmente necesita una función solo una vez por tipo.

La llamada new en javascript establece automáticamente el constructor en el prototipo. Si está sobrescribiendo el prototipo, debe configurar el constructor manualmente.

Herencia en javascript no tiene nada que ver con super. Entonces, si tiene una subclase, la única posibilidad de llamar al superconstructor es por su nombre.

1

no estoy 100% seguro, pero creo que la diferencia es que el segundo ejemplo, simplemente duplica el contenido de la clase de coche en el superdeportivo object, mientras que el primero vincula el prototipo SuperCar a la clase Car, por lo que los cambios de tiempo de ejecución en la clase Car afectan también a la clase SuperCar.

136

Para agregar a Norbert Hartl's answer, no es necesario SuperCar.prototype.constructor, pero algunas personas lo utilizan como una forma conveniente de obtener la función de construcción de un objeto (objetos SuperCar en este caso).

Sólo desde el primer ejemplo, Car.call (esto, el nombre) se encuentra en la función Supercar constructor porque cuando se hace esto:

var mySuperCar = new SuperCar("SuperCar"); 

Esto es lo que hace JavaScript:

  1. Un se crea una instancia del objeto nuevo en blanco.
  2. El prototipo interno del objeto nuevo está configurado en Car.
  3. Se ejecuta la función del constructor SuperCar.
  4. El objeto terminado se devuelve y se establece en mySuperCar.

Note como JavaScript no llamó coche para usted. Los prototipos, tal como son, cualquier propiedad o método que no se haya configurado para SuperCar se buscará en el automóvil. A veces esto es bueno, p. SuperCar no tiene un método de Drive, pero puede compartir el de Car, por lo que todos los SuperCars usarán el mismo método de Drive. Otras veces no desea compartir, como que cada SuperCar tenga su propio Nombre. Entonces, ¿cómo se puede establecer el nombre de cada SuperCar para que sea propio? También podemos establecer this.Name dentro de la función Supercar constructor:

function SuperCar(name){ 
    this.Name = name; 
} 

Esto funciona, pero espera un segundo. ¿No hicimos exactamente lo mismo en el constructor de coches? No quiero repetirnos Dado que Car ya establece el nombre, simplemente vamos a llamarlo.

function SuperCar(name){ 
    this = Car(name); 
} 

Vaya, nunca quieren cambiar la referencia especial this objeto. ¿Recuerdas los 4 pasos? Cuídate de ese objeto que JavaScript te dio, porque es la única manera de mantener el precioso prototipo de enlace interno entre tu objeto SuperCar y tu coche. Entonces, ¿cómo establecemos el nombre, sin repetirnos y sin tirar nuestro objeto fresco SuperCar, JavaScript pasó tanto esfuerzo especial para prepararse para nosotros?

dos cosas. Uno: el significado de this es flexible. Dos: el coche es una función. Es posible llamar a Car, no con un objeto prístino y recién instanciado, sino con un objeto SuperCar, por ejemplo. Eso nos da la solución final, que forma parte del primer ejemplo en su pregunta:

function SuperCar(name){ 
    Car.call(this, name); 
} 

Como una función, se permite coches que se invoca con la función call method, que cambia el significado de this dentro del coche a la Instancia de SuperCar que estamos construyendo. ¡Presto! Ahora cada SuperCar obtiene su propia propiedad de Nombre.

Para concluir, Car.call(this, name) en el constructor de SuperCar le da a cada objeto nuevo de SuperCar su propia propiedad de nombre exclusivo, pero sin duplicar el código que ya está en el coche.

Los prototipos no son de miedo, una vez que las entiende, pero no lo son tanto como el modelo clásico de programación orientada a objetos de clases/inheritence en absoluto. Escribí un artículo sobre the prototypes concept in JavaScript. Está escrito para un motor de juego que usa JavaScript, pero es el mismo motor de JavaScript utilizado por Firefox, por lo que todo debe ser relevante. Espero que esto ayude.

+4

"SuperCar.prototype.constructor" es necesario si lo desea ' Object.getPrototypeOf' emula en los motores heredados para funcionar – Raynos

+3

El enlace actual al "concepto de prototipos en Javascript" está roto. ¿Hay otro lugar donde pueda leer este artículo? – shockawave123

8

Norbert, deberá tener en cuenta que su primer ejemplo es más o menos lo que Douglas Crockford llama herencia pseudoclassical. cosas algo a tener en cuenta en esto:

  1. Va a llamar al constructor del coche dos veces, una desde la línea de SuperCar.prototype = nuevo coche() y el otro de la línea de "constructor de robar" Car.call (esto .. .you puede crear un método de ayuda para heredar prototipos lugar y el constructor de coches sólo tendrá que ejecutar una vez haciendo que la instalación sea más eficiente.
  2. la línea = Supercar SuperCar.prototype.constructor le permitirá utilizar instanceof para identificar el constructor. algunas personas quieren que esto otros sólo evitar el uso de instanceof
  3. Referencia vars como:. arr var = [ 'uno', 'dos'] cuando se define en el super (por ejemplo coches) obtendrán compartida por todas las instancias Esto significa inst1.arr. pu sh ['three'], inst2.arr.push ['four'], etc., aparecerán para todas las instancias!Esencialmente, comportamiento estático que probablemente no desee.
  4. Su segundo bloque define el método fly en el constructor. Esto significa que cada vez que se llame, se creará un "objeto de método". ¡Mejor usar un prototipo para métodos! Sin embargo, PUEDE guardarlo en el constructor si lo desea, solo necesita protegerlo para que solo inicialice el prototipo literal una vez (pseudo): if (SuperCar.prototype.myMethod! = 'Function') ... luego defina su prototipo literal.
  5. 'Por qué llamar a Car.call (this, name) ....': No tengo tiempo para mirar detenidamente su código, así que puedo estar equivocado, pero esto generalmente es para que cada instancia pueda mantener su propio estado para arreglar el problema del comportamiento 'staticy' del prototipo de encadenamiento que describí anteriormente.

Por último, me gustaría mencionar que tengo varios ejemplos de código JavaScript TDD herencia que trabaja aquí: TDD JavaScript Inheritance Code and Essay Me encantaría recibir sus comentarios ya que estoy esperando para mejorarlo y mantenerlo de código abierto . El objetivo es ayudar a los programadores clásicos a actualizarse rápidamente con JavaScript y complementar el estudio de los libros de Crockford y Zakas.

+1

Me encontré con el punto (1) antes de ahora. Encontré que si no usaba la nueva palabra clave y solo usaba Superclass.call (esto) (así que SuperCar = {Car.call (this);}; SuperCar.prototype = Car;) que esto parecía funcionar. ¿Hay alguna razón para no hacer esto? (disculpas por el necro) – obie

+0

Viniendo de * classic * lenguajes OOP, siempre he encontrado * extraño * la necesidad de crear una instancia 'nueva' * solo * para llenar la cadena de prototipos – superjos

+0

Buen libro. Debe tener en cuenta que el enlace en la parte superior de la página de github está roto, aunque, por supuesto, se puede encontrar en los contenidos. –

0
function abc() { 
} 

métodos de prototipo y la propiedad creadas para abc función

abc.prototype.testProperty = 'Hi, I am prototype property'; 
abc.prototype.testMethod = function() { 
    alert('Hi i am prototype method') 
} 

Creación de nuevas instancias para ABC función

var objx = new abc(); 

console.log(objx.testProperty); // will display Hi, I am prototype property 
objx.testMethod();// alert Hi i am prototype method 

var objy = new abc(); 

console.log(objy.testProperty); //will display Hi, I am prototype property 
objy.testProperty = Hi, I am over-ridden prototype property 

console.log(objy.testProperty); //will display Hi, I am over-ridden prototype property 

http://astutejs.blogspot.in/2015/10/javascript-prototype-is-easy.html