Digamos que tiene el siguiente código:
function A() {
function modify() {
x = 300;
y = 400;
}
var c = new C();
}
function B() {
function modify(){
x = 3000;
y = 4000;
}
var c = new C();
}
C = function () {
var x = 10;
var y = 20;
function modify() {
x = 30;
y = 40;
};
modify();
alert("The sum is: " + (x+y));
}
Ahora la pregunta es, si hay alguna manera en la que puedo reemplazar el método modify
de C
los métodos que se encuentran en A
y B
. En Java, usaría la super
palabra clave, pero ¿cómo puede lograr algo como esto en JavaScript?
javascript
oop
overriding
Daniel Nastase
fuente
fuente
modify
no es un método, sino una función anidada; hay una diferencia entre esos dos ...super
palabra clave para acceder a los campos y métodos no privados de una superclase. No lo usa para anularlos.Respuestas:
Editar: ¡Han pasado seis años desde que se escribió la respuesta original y muchas cosas han cambiado!
¡Buena suerte!
La herencia de JavaScript se ve un poco diferente a la de Java. Así es como se ve el sistema de objetos de JavaScript nativo:
// Create a class function Vehicle(color){ this.color = color; } // Add an instance method Vehicle.prototype.go = function(){ return "Underway in " + this.color; } // Add a second class function Car(color){ this.color = color; } // And declare it is a subclass of the first Car.prototype = new Vehicle(); // Override the instance method Car.prototype.go = function(){ return Vehicle.prototype.go.call(this) + " car" } // Create some instances and see the overridden behavior. var v = new Vehicle("blue"); v.go() // "Underway in blue" var c = new Car("red"); c.go() // "Underway in red car"
Desafortunadamente, esto es un poco feo y no incluye una forma muy agradable de "super": tienes que especificar manualmente el método de las clases principales que quieres llamar. Como resultado, hay una variedad de herramientas para hacer que la creación de clases sea más agradable. Intente buscar en Prototype.js, Backbone.js o una biblioteca similar que incluya una sintaxis más agradable para hacer OOP en js.
fuente
Dado que este es un gran éxito en Google, me gustaría dar una respuesta actualizada.
El uso de clases de ES6 hace que la herencia y la anulación de métodos sea mucho más fácil:
'use strict'; class A { speak() { console.log("I'm A"); } } class B extends A { speak() { super.speak(); console.log("I'm B"); } } var a = new A(); a.speak(); // Output: // I'm A var b = new B(); b.speak(); // Output: // I'm A // I'm B
La
super
palabra clave se refiere a la clase principal cuando se usa en la clase heredada. Además, todos los métodos de la clase principal están vinculados a la instancia del niño, por lo que no tiene que escribirsuper.method.apply(this);
.En cuanto a la compatibilidad: la tabla de compatibilidad de ES6 muestra solo las versiones más recientes de las clases de soporte de los principales jugadores (en su mayoría). Los navegadores V8 los han tenido desde enero de este año (Chrome y Opera), y Firefox, usando el motor SpiderMonkey JS, verá clases el próximo mes con su lanzamiento oficial de Firefox 45. En el lado móvil, Android aún no es compatible con esta función, mientras que iOS 9, lanzado hace cinco meses, tiene soporte parcial.
Afortunadamente, existe Babel , una biblioteca JS para recompilar código Harmony en código ES5. Las clases y muchas otras características interesantes de ES6 pueden hacer que su código Javascript sea mucho más legible y fácil de mantener.
fuente
Once debería evitar emular OO clásico y usar OO prototípico en su lugar. Una buena biblioteca de utilidades para OO prototípicos son los rasgos .
En lugar de sobrescribir métodos y configurar cadenas de herencia (siempre se debe favorecer la composición de objetos sobre la herencia de objetos), debe agrupar funciones reutilizables en rasgos y crear objetos con ellos.
Ejemplo en vivo
var modifyA = { modify: function() { this.x = 300; this.y = 400; } }; var modifyB = { modify: function() { this.x = 3000; this.y = 4000; } }; C = function(trait) { var o = Object.create(Object.prototype, Trait(trait)); o.modify(); console.log("sum : " + (o.x + o.y)); return o; } //C(modifyA); C(modifyB);
fuente
En su ejemplo, modificar () es una función privada, a la que no se podrá acceder desde ningún lugar excepto dentro de su definición A, B o C. Debería declararlo como
this.modify = function(){}
C no tiene ninguna referencia a sus padres, a menos que se lo pase a C. Si C está configurado para heredar de A o B, heredará sus métodos públicos (no sus funciones privadas como ha definido modified ()). Una vez que C hereda los métodos de su padre, puede anular los métodos heredados.
fuente
el método
modify()
que llamó en el último se llama en contexto global si desea anularmodify()
primero debe heredarA
oB
.Quizás estás intentando hacer esto:
En este caso
C
heredaA
function A() { this.modify = function() { alert("in A"); } } function B() { this.modify = function() { alert("in B"); } } C = function() { this.modify = function() { alert("in C"); }; C.prototype.modify(); // you can call this method where you need to call modify of the parent class } C.prototype = new A();
fuente
C.prototype.modify()
tendría elthis
valor incorrecto . Es decir, enC.prototype
lugar de la instancia de c. Utilice,.call(this)
pero su respuesta es solo un duplicado :)No, a menos que haga todas las variables "públicas", es decir, las haga miembros de
Function
laprototype
propiedad directamente o mediante la propiedad.var C = function( ) { this.x = 10 , this.y = 20 ; this.modify = function( ) { this.x = 30 , this.y = 40 ; console.log("(!) C >> " + (this.x + this.y) ) ; } ; } ; var A = function( ) { this.modify = function( ) { this.x = 300 , this.y = 400 ; console.log("(!) A >> " + (this.x + this.y) ) ; } ; } ; A.prototype = new C ; var B = function( ) { this.modify = function( ) { this.x = 3000 , this.y = 4000 ; console.log("(!) B >> " + (this.x + this.y) ) ; } ; } ; new C( ).modify( ) ; new A( ).modify( ) ; new B( ).modify( ) ;
Notarás algunos cambios.
Lo más importante es que la llamada al constructor de supuestas "superclases" ahora está implícita dentro de esta línea:
<name>.prototype = new C ;
Ambos
A
yB
ahora tendrán miembros modificables individualmentex
yy
lo que no sería el caso si hubiéramos escrito en su... = C
lugar.Entonces,
x
,y
ymodify
son todos los miembros "públicos" de manera que la asignación de una diferenteFunction
a ellos<name>.prototype.modify = function( ) { /* ... */ }
"anulará" el original
Function
con ese nombre.Por último, la llamada a
modify
no se puede hacer en laFunction
declaración porque la llamada implícita a la "superclase" se volvería a ejecutar cuando establezcamos la supuesta "superclase" en laprototype
propiedad de las supuestas "subclases".Pero bueno, así es más o menos cómo harías este tipo de cosas en JavaScript.
HTH,
FK
fuente
<name>.prototype = new C;
todos modosObjects
compartirían el mismo miembroC
si no crea una instancia de unC
objeto. Por lo tanto, cambiarx
enA
cambiaríax
enC
y, por lo tanto, cambiaríax
enB
. Lo cual es obviamente indeseable.A
yB
heredarC
. Si faltara esa línea, ese no sería el caso. De hecho, el único prototipo tantoA
, así comoB
sería "sombra" tendría acceso a que en ese caso seríaObject.prototype
.x
, por lo tanto, ensombrecen a todos los miembros. ¿Cuál es el punto de poner C en el prototipo si no lo estás usando? Es un código muerto.y
modify
C
function A() { var c = new C(); c.modify = function(){ c.x = 123; c.y = 333; } c.sum(); } function B() { var c = new C(); c.modify = function(){ c.x = 999; c.y = 333; } c.sum(); } C = function () { this.x = 10; this.y = 20; this.modify = function() { this.x = 30; this.y = 40; }; this.sum = function(){ this.modify(); console.log("The sum is: " + (this.x+this.y)); } } A(); B();
fuente