tutorial - Comprender la herencia prototípica en JavaScript
prototype javascript tutorial (5)
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é?
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 agregó los métodos de Drive
y Fly
utilizando un prototype
, pero no los declara como this.Drive
método de this.Drive
dentro Car
clase Car
y esto. ¿Lo this.Fly
en la clase SuperCar
?
¿Por qué SuperCar.prototype.constructor
necesita volverse a establecer en SuperCar
? ¿Se invalida la propiedad del constructor cuando se establece el prototype
? Comenté esta línea y nada cambió.
Por qué llamar a Car.call(this, name);
en el constructor de SuperCar
? ¿No se ''heredarán'' las propiedades y los métodos del Car
cuando lo hago?
var myCar = new Car("Car");
Los dos bloques difieren de una manera que en el primer ejemplo Drive()
solo existirá una vez, mientras que en el segundo enfoque existirá Drive()
por instancia (Cada vez que haga un new Car()
se creará nuevamente la drive()
función drive()
) . 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 new
llamada en javascript establece automáticamente el constructor en el prototipo. Si está sobrescribiendo el prototipo, debe configurar el constructor manualmente.
La herencia en javascript no tiene nada como super
. Entonces, si tiene una subclase, la única posibilidad de llamar al superconstructor es por su nombre.
No estoy 100% seguro, pero creo que la diferencia es que el segundo ejemplo simplemente duplica el contenido de la clase Car en el objeto SuperCar, mientras que el primero vincula el prototipo SuperCar a la clase Car, de modo que el tiempo de ejecución cambia a La clase de auto afecta la clase SuperCar también.
Norbert, debes notar que tu primer ejemplo es más o menos lo que Douglas Crockford llama herencia pseudoclassical. Algo que hay que tener en cuenta sobre esto:
- Llamarás al constructor del coche dos veces, una desde la línea SuperCar.prototype = new Car () y la otra desde la línea Car.call "constructor robo" (esto ... puedes crear un método de ayuda para heredar prototipos y tu El constructor de automóviles solo tendrá que ejecutar una vez haciendo que la configuración sea más eficiente.
- La línea SuperCar.prototype.constructor = SuperCar le permitirá usar instanceof para identificar el constructor. Algunas personas quieren que los demás simplemente eviten usar instanceof
- Los valores de referencia como: var arr = [''uno'', ''dos''] cuando se definen en el super (ej. Coche) serán compartidos por TODAS las instancias. Esto significa que inst1.arr.push [''three''], inst2.arr.push [''four''], etc. aparecerán en todas las instancias. Esencialmente, comportamiento estático que probablemente no desee.
- Tu 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.
- ''¿Por qué llamar a Car.call (esto, nombre) ...'': no tengo tiempo para mirar cuidadosamente su código, así que puedo estar equivocado, pero esto es generalmente así para que cada instancia pueda mantener su propio estado para arreglar el problema de comportamiento ''estaticy'' del prototipo de encadenamiento que describí anteriormente.
Por último, me gustaría mencionar que tengo varios ejemplos de código de herencia de JavaScript TDD que funciona aquí: código de herencia de JavaScript TDD y ensayo. Me encantaría recibir sus comentarios ya que espero mejorarlo y mantenerlo 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.
Para agregar a la respuesta de Norbert Hartl , 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 de SuperCar en este caso).
Solo desde el primer ejemplo, Car.call (este, nombre) está en la función constructora SuperCar porque cuando haces esto:
var mySuperCar = new SuperCar("SuperCar");
Esto es lo que hace JavaScript:
- Se crea una instancia de un objeto nuevo y en blanco.
- El prototipo interno del objeto nuevo está configurado en Car.
- La función constructor de SuperCar se ejecuta.
- El objeto terminado se devuelve y se establece en mySuperCar.
Observe cómo JavaScript no llamó a Car por 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, por ejemplo, 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? Puede establecer this.Name dentro de la función del constructor de SuperCar:
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 querrá cambiar la referencia especial de 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 es parte del primer ejemplo en su pregunta:
function SuperCar(name){
Car.call(this, name);
}
Como función, se puede invocar a Car con el método de llamada de la función, que cambia el significado de this
dentro de Car a la instancia de SuperCar que estamos creando. ¡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 nuevo objeto de SuperCar su propia propiedad de Nombre exclusivo, pero sin duplicar el código que ya está en Car.
Los prototipos no dan miedo una vez que los entiendes, pero no se parecen mucho al modelo OOP clásico de clase / herencia. Escribí un artículo sobre el concepto de prototipos en 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.
function abc() {
}
Prototipos de métodos y propiedades creados para la función abc
abc.prototype.testProperty = ''Hi, I am prototype property'';
abc.prototype.testMethod = function() {
alert(''Hi i am prototype method'')
}
Creando nuevas instancias para la función abc
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