Metodi di sovrascrittura JavaScript

Diciamo che hai il codice seguente:

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

Ora la domanda è, se c’è un modo in cui posso sovrascrivere il metodo modify da C con i metodi che sono in A e B. In Java useresti la parola chiave super, ma come puoi ottenere qualcosa di simile in JavaScript?

Edit: Sono passati sei anni da quando è stata scritta la risposta originale e molto è cambiato!

  • Se stai utilizzando una versione più recente di JavaScript, possibilmente compilata con uno strumento come Babel , puoi utilizzare classi reali .
  • Se stai usando i costruttori di componenti di class forniti da Angular o React , ti consigliamo di consultare i documenti per quel framework.
  • Se stai usando ES5 e fai le classi “finte” a mano usando i prototipi, la risposta qui sotto è ancora corretta.

In bocca al lupo!


L’ereditarietà di JavaScript è leggermente diversa da Java. Ecco come appare il sistema di oggetti 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" 

Sfortunatamente questo è un po ‘brutto e non include un modo molto carino di “super”: devi specificare manualmente il metodo delle classi genitore che vuoi chiamare. Di conseguenza, ci sono una varietà di strumenti per rendere più piacevole la creazione di classi. Prova a guardare Prototype.js, Backbone.js o una libreria simile che include una syntax migliore per eseguire OOP in js.

Dal momento che questo è un successo su Google, vorrei dare una risposta aggiornata.

L’utilizzo delle classi ES6 semplifica molto l’ereditarietà e il metodo:

 '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 parola chiave super riferisce alla class genitore quando viene utilizzata nella class ereditaria. Inoltre, tutti i metodi sulla class genitore sono legati all’istanza del bambino, quindi non devi scrivere super.method.apply(this); .

Per quanto riguarda la compatibilità: la tabella di compatibilità ES6 mostra solo le versioni più recenti delle principali classi di supporto dei giocatori (principalmente). I browser V8 li hanno acquisiti dal gennaio di quest’anno (Chrome e Opera), e Firefox, utilizzando il motore SpiderMonkey JS, vedrà le classi il prossimo mese con la loro versione ufficiale di Firefox 45. Sul lato mobile, Android non supporta ancora questa funzione, mentre iOS 9, versione cinque mesi fa, ha supporto parziale.

Fortunatamente, c’è Babel , una libreria JS per ricompilare il codice Harmony nel codice ES5. Classi e molte altre interessanti funzionalità di ES6 possono rendere il tuo codice Javascript molto più leggibile e gestibile.

Una volta dovrebbe evitare di emulare OO classico e utilizzare invece OO prototipo. Una bella libreria di utilità per OO prototipo è i tratti .

Invece di sovrascrivere i metodi e impostare le catene di ereditarietà (si dovrebbe sempre favorire la composizione degli oggetti rispetto all’ereditarietà degli oggetti), si dovrebbero raggruppare funzioni riutilizzabili in tratti e creare oggetti con questi.

Esempio dal 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 : " + (ox + oy)); return o; } //C(modifyA); C(modifyB); 

modify () nel tuo esempio è una funzione privata, che non sarà accessibile da nessuna parte ma all’interno della tua definizione A, B o C. Dovresti dichiararlo come

 this.modify = function(){} 

C non ha riferimenti ai suoi genitori, a meno che tu non lo passi a C. Se C è impostato per ereditare da A o B, erediterà i suoi metodi pubblici (non le sue funzioni private come hai definito modify ()). Una volta che C eredita i metodi dal suo genitore, è ansible sovrascrivere i metodi ereditati.

il metodo modify() che hai chiamato nell’ultimo è chiamato nel contesto globale se vuoi sovrascrivere modify() devi prima ereditare A o B

Forse stai cercando di fare questo:

In questo caso C eredita A

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

No, a meno che non si rendano “pubbliche” tutte le variabili, ovvero rendendole membri della Function direttamente o tramite la proprietà del prototype .

 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( ) ; 
  • testalo qui

Noterai alcune modifiche.

Ancora più importante la chiamata al supposto costruttore di “super-classi” è ora implicita in questa linea:

 .prototype = new C ; 

Sia A che B ora avranno membri modificabili individualmente x e y che non sarebbero il caso se avremmo scritto ... = C invece.

Quindi, x , y e modify sono tutti membri “pubblici” in modo che assegnino loro una Function diversa

  .prototype.modify = function( ) { /* ... */ } 

“sostituirà” la Function originale con quel nome.

Infine, la chiamata a modify non può essere eseguita nella dichiarazione Function perché la chiamata implicita alla “super-class” verrebbe quindi eseguita nuovamente quando impostiamo la supposta “super-class” alla proprietà prototype delle “sottoclassi” presunte. “.

Ma bene, questo è più o meno come si farebbe questo genere di cose in JavaScript.

HTH,

FK

 function A() { var c = new C(); c.modify = function(){ cx = 123; cy = 333; } c.sum(); } function B() { var c = new C(); c.modify = function(){ cx = 999; cy = 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();