Come ereditare da una class in javascript?

In PHP / Java si può fare:

class Sub extends Base { } 

E automaticamente tutti i metodi, le proprietà, i campi, ecc. Pubblici e protetti della class Super diventano parte della class Sub che può essere sovrascritta se necessario.

Qual è l’equivalente per quello in Javascript?

Ho cambiato il modo in cui lo faccio ora, cerco di evitare di utilizzare le funzioni di costruzione e la loro proprietà di prototype , ma la mia vecchia risposta dal 2010 è ancora in fondo. Ora preferisco Object.create() . Object.create è disponibile in tutti i browser moderni.

Dovrei notare che Object.create solito è molto più lento di usare new con un costruttore di funzioni.

 //The prototype is just an object when you use `Object.create()` var Base = {}; //This is how you create an instance: var baseInstance = Object.create(Base); //If you want to inherit from "Base": var subInstance = Object.create(Object.create(Base)); //Detect if subInstance is an instance of Base: console.log(Base.isPrototypeOf(subInstance)); //True 

jsfiddle

Uno dei grandi vantaggi dell’utilizzo di Object.create è la possibilità di passare in un argomento defineProperties , che offre un controllo significativo su come è ansible accedere e classificare le proprietà della class, e utilizzo anche le funzioni per creare istanze, che fungono da costruttori in un certo senso, come si può fare l’inizializzazione alla fine invece di restituire l’istanza.

 var Base = {}; function createBase() { return Object.create(Base, { doSomething: { value: function () { console.log("Doing something"); }, }, }); } var Sub = createBase(); function createSub() { return Object.create(Sub, { doSomethingElse: { value: function () { console.log("Doing something else"); }, }, }); } var subInstance = createSub(); subInstance.doSomething(); //Logs "Doing something" subInstance.doSomethingElse(); //Logs "Doing something else" console.log(Base.isPrototypeOf(subInstance)); //Logs "true" console.log(Sub.isPrototypeOf(subInstance)); //Logs "true 

jsfiddle

Questa è la mia risposta originale del 2010:

 function Base ( ) { this.color = "blue"; } function Sub ( ) { } Sub.prototype = new Base( ); Sub.prototype.showColor = function ( ) { console.log( this.color ); } var instance = new Sub ( ); instance.showColor( ); //"blue" 

In JavaScript non hai classi ma puoi ottenere ereditarietà e riutilizzo del comportamento in molti modi:

Eredità pseudo-classica (attraverso la prototipazione):

 function Super () { this.member1 = 'superMember1'; } Super.prototype.member2 = 'superMember2'; function Sub() { this.member3 = 'subMember3'; //... } Sub.prototype = new Super(); 

Dovrebbe essere usato con il new operatore:

 var subInstance = new Sub(); 

Applicazione della funzione o “concatenamento del costruttore”:

 function Super () { this.member1 = 'superMember1'; this.member2 = 'superMember2'; } function Sub() { Super.apply(this, arguments); this.member3 = 'subMember3'; } 

Questo approccio dovrebbe essere utilizzato anche con il new operatore:

 var subInstance = new Sub(); 

La differenza con il primo esempio è che quando apply il Super constructor a this object all’interno di Sub , esso aggiunge le proprietà assegnate a this su Super , direttamente sulla nuova istanza, ad esempio subInstance contiene le proprietà member1 e member2 direttamente ( subInstance.hasOwnProperty('member1') == true; ).

Nel primo esempio, tali proprietà vengono raggiunte attraverso la catena del prototipo , esistono su un object interno [[Prototype]] .

Eredità parassita o Power Constructors:

 function createSuper() { var obj = { member1: 'superMember1', member2: 'superMember2' }; return obj; } function createSub() { var obj = createSuper(); obj.member3 = 'subMember3'; return obj; } 

Questo approccio si basa fondamentalmente sul “potenziamento degli oggetti”, non è necessario utilizzare il new operatore e, come puoi vedere, this parola chiave non è coinvolta.

 var subInstance = createSub(); 

ECMAScript 5th Ed. Metodo Object.create :

 // Check if native implementation available if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} // empty constructor F.prototype = o; // set base object as prototype return new F(); // return empty object with right [[Prototype]] }; } var superInstance = { member1: 'superMember1', member2: 'superMember2' }; var subInstance = Object.create(superInstance); subInstance.member3 = 'subMember3'; 

Il metodo di cui sopra è una tecnica di ereditarietà prototipale proposta da Crockford .

Le istanze dell’object ereditano da altre istanze di oggetti, questo è tutto.

Questa tecnica può essere migliore della semplice “potenziamento degli oggetti” perché le proprietà ereditate non vengono copiate su tutte le nuove istanze di object, poiché l’object di base è impostato come [[Prototype]] dell’object esteso , nell’esempio precedente subInstance contiene fisicamente solo la proprietà member3 .

Per coloro che raggiungono questa pagina nel 2015 o dopo

Con l’ultima versione dello standard ECMAScript (ES6) , è ansible utilizzare estensioni de keywork

Nota che la definizione della class non è un object regolare object quindi non ci sono virgole tra i membri della class. Per creare un’istanza di una class, è necessario utilizzare la new parola chiave. Per ereditare da una class base, utilizzare extends :

 class Vehicle { constructor(name) { this.name = name; this.kind = 'vehicle'; } getName() { return this.name; } } // Create an instance var myVehicle = new Vehicle('rocky'); myVehicle.getName(); // => 'rocky' 

Per ereditare da una class base, utilizzare extends :

 class Car extends Vehicle { constructor(name) { super(name); this.kind = 'car' } } var myCar = new Car('bumpy'); myCar.getName(); // => 'bumpy' myCar instanceof Car; // => true myCar instanceof Vehicle; // => true 

Dalla class derivata, puoi usare super da qualsiasi costruttore o metodo per accedere alla sua class base:

  • Per chiamare il costruttore genitore, utilizzare super().
  • Per chiamare un altro membro, utilizzare, ad esempio, super.getName() .

C’è altro nell’uso delle classi. Se vuoi approfondire l’argomento, ti consiglio ” Classes in ECMAScript 6 ” del Dr. Axel Rauschmayer. *

fonte

Bene, in JavaScript non esiste “l’ereditarietà della class”, esiste solo “l’ereditarietà del prototipo”. Quindi non fai un “camion” di class e quindi contrassegnalo come sottoclass di “automobile”. Invece, si crea un object “Jack” e si dice che usi “John” come prototipo. Se John sa, quanto “4 + 4” è, allora anche Jack lo sa.

Vi suggerisco di leggere l’articolo di Douglas Crockford sull’ereditarietà del prototipo qui: http://javascript.crockford.com/prototypal.html Mostra anche come si può fare in modo che JavaScript abbia un’eredità “simile” come in altre lingue OO e poi spiega che questo in realtà significa rompere javaScript in un modo che non doveva essere usato.

Trovo che questa citazione sia la più illuminante:

In sostanza, una “class” JavaScript è solo un object Function che funge da costruttore più un object prototipo collegato. ( Fonte: Guru Katz )

Mi piace usare i costruttori piuttosto che gli oggetti, quindi sono parziale al metodo di “eredità pseudo-classica” qui descritto da CMS . Ecco un esempio di ereditarietà multipla con una catena di prototipi :

 // Lifeform "Class" (Constructor function, No prototype) function Lifeform () { this.isLifeform = true; } // Animal "Class" (Constructor function + prototype for inheritance) function Animal () { this.isAnimal = true; } Animal.prototype = new Lifeform(); // Mammal "Class" (Constructor function + prototype for inheritance) function Mammal () { this.isMammal = true; } Mammal.prototype = new Animal(); // Cat "Class" (Constructor function + prototype for inheritance) function Cat (species) { this.isCat = true; this.species = species } Cat.prototype = new Mammal(); // Make an instance object of the Cat "Class" var tiger = new Cat("tiger"); console.log(tiger); // The console outputs a Cat object with all the properties from all "classs" console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform); // Outputs: true true true true // You can see that all of these "is" properties are available in this object // We can check to see which properties are really part of the instance object console.log( "tiger hasOwnProperty: " ,tiger.hasOwnProperty("isLifeform") // false ,tiger.hasOwnProperty("isAnimal") // false ,tiger.hasOwnProperty("isMammal") // false ,tiger.hasOwnProperty("isCat") // true ); // New properties can be added to the prototypes of any // of the "classs" above and they will be usable by the instance Lifeform.prototype.A = 1; Animal.prototype.B = 2; Mammal.prototype.C = 3; Cat.prototype.D = 4; console.log(tiger.A, tiger.B, tiger.C, tiger.D); // Console outputs: 1 2 3 4 // Look at the instance object again console.log(tiger); // You'll see it now has the "D" property // The others are accessible but not visible (console issue?) // In the Chrome console you should be able to drill down the __proto__ chain // You can also look down the proto chain with Object.getPrototypeOf // (Equivalent to tiger.__proto__) console.log( Object.getPrototypeOf(tiger) ); // Mammal console.log( Object.getPrototypeOf(Object.getPrototypeOf(tiger)) ); // Animal // Etc. to get to Lifeform 

Ecco un’altra buona risorsa da MDN , ed ecco un jsfiddle in modo che tu possa provarlo .

L’ereditarietà di Javascript è leggermente diversa da Java e PHP, perché in realtà non ha classi. Invece ha oggetti prototipo che forniscono metodi e variabili membro. Puoi concatenare questi prototipi per fornire l’ereditarietà degli oggetti. Lo schema più comune che ho trovato durante la ricerca di questa domanda è descritto sulla rete di sviluppatori Mozilla . Ho aggiornato il loro esempio per includere una chiamata a un metodo superclass e per mostrare il log in un messaggio di avviso:

 // Shape - superclass function Shape() { this.x = 0; this.y = 0; } // superclass method Shape.prototype.move = function(x, y) { this.x += x; this.y += y; log += 'Shape moved.\n'; }; // Rectangle - subclass function Rectangle() { Shape.call(this); // call super constructor. } // subclass extends superclass Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle; // Override method Rectangle.prototype.move = function(x, y) { Shape.prototype.move.call(this, x, y); // call superclass method log += 'Rectangle moved.\n'; } var log = ""; var rect = new Rectangle(); log += ('Is rect an instance of Rectangle? ' + (rect instanceof Rectangle) + '\n'); // true log += ('Is rect an instance of Shape? ' + (rect instanceof Shape) + '\n'); // true rect.move(1, 1); // Outputs, 'Shape moved.' alert(log); 

non puoi (nel senso classico). Javascript è un linguaggio prototipo. Noterai che non si dichiara mai una “class” in Javascript; si limitano a definire lo stato e i metodi di un object. Per produrre eredità, prendi un object e lo prototipi. Il prototipo viene esteso con nuove funzionalità.

Puoi usare la libreria .inheritWith e .fastClass . È più veloce della maggior parte delle librerie popolari e talvolta persino più veloce della versione nativa.

Molto facile da usare:

 function Super() { this.member1 = "superMember";//instance member }.define({ //define methods on Super's prototype method1: function() { console.log('super'); } //prototype member }.defineStatic({ //define static methods directly on Super function staticMethod1: function() { console.log('static method on Super'); } }); var Sub = Super.inheritWith(function(base, baseCtor) { return { constructor: function() {//the Sub constructor that will be returned to variable Sub this.member3 = 'subMember3'; //instance member on Sub baseCtor.apply(this, arguments);//call base construcor and passing all incoming arguments }, method1: function() { console.log('sub'); base.method1.apply(this, arguments); //call the base class' method1 function } } 

uso

 var s = new Sub(); s.method1(); //prints: //sub //super 
 function Person(attr){ this.name = (attr && attr.name)? attr.name : undefined; this.birthYear = (attr && attr.birthYear)? attr.birthYear : undefined; this.printName = function(){ console.log(this.name); } this.printBirthYear = function(){ console.log(this.birthYear); } this.print = function(){ console.log(this.name + '(' +this.birthYear+ ')'); } } function PersonExt(attr){ Person.call(this, attr); this.print = function(){ console.log(this.name+ '-' + this.birthYear); } this.newPrint = function(){ console.log('New method'); } } PersonExt.prototype = new Person(); // Init object and call methods var p = new Person({name: 'Mr. A', birthYear: 2007}); // Parent method p.print() // Mr. A(2007) p.printName() // Mr. A var pExt = new PersonExt({name: 'Mr. A', birthYear: 2007}); // Overwriten method pExt.print() // Mr. A-2007 // Extended method pExt.newPrint() // New method // Parent method pExt.printName() // Mr. A 

Dopo aver letto molti post, ho trovato questa soluzione ( jsfiddle qui ). Il più delle volte non ho bisogno di qualcosa di più sofisticato

 var Class = function(definition) { var base = definition.extend || null; var construct = definition.construct || definition.extend || function() {}; var newClass = function() { this._base_ = base; construct.apply(this, arguments); } if (definition.name) newClass._name_ = definition.name; if (definition.extend) { var f = function() {} f.prototype = definition.extend.prototype; newClass.prototype = new f(); newClass.prototype.constructor = newClass; newClass._extend_ = definition.extend; newClass._base_ = definition.extend.prototype; } if (definition.statics) for (var n in definition.statics) newClass[n] = definition.statics[n]; if (definition.members) for (var n in definition.members) newClass.prototype[n] = definition.members[n]; return newClass; } var Animal = Class({ construct: function() { }, members: { speak: function() { console.log("nuf said"); }, isA: function() { return "animal"; } } }); var Dog = Class({ extend: Animal, construct: function(name) { this._base_(); this.name = name; }, statics: { Home: "House", Food: "Meat", Speak: "Barks" }, members: { name: "", speak: function() { console.log( "ouaf !"); }, isA: function(advice) { return advice + " dog -> " + Dog._base_.isA.call(this); } } }); var Yorkshire = Class({ extend: Dog, construct: function(name,gender) { this._base_(name); this.gender = gender; }, members: { speak: function() { console.log( "ouin !"); }, isA: function(advice) { return "yorkshire -> " + Yorkshire._base_.isA.call(this,advice); } } }); var Bulldog = function() { return _class_ = Class({ extend: Dog, construct: function(name) { this._base_(name); }, members: { speak: function() { console.log( "OUAF !"); }, isA: function(advice) { return "bulldog -> " + _class_._base_.isA.call(this,advice); } } })}(); var animal = new Animal("Maciste"); console.log(animal.isA()); animal.speak(); var dog = new Dog("Sultan"); console.log(dog.isA("good")); dog.speak(); var yorkshire = new Yorkshire("Golgoth","Male"); console.log(yorkshire.isA("bad")); yorkshire.speak(); var bulldog = new Bulldog("Mike"); console.log(bulldog.isA("nice")); bulldog.speak(); 

Grazie alla risposta di CMS e dopo aver giocato per un po ‘con prototype e Object.create e cosa no, sono riuscito a trovare una soluzione chiara per la mia ereditarietà usando apply come mostrato qui:

 var myNamespace = myNamespace || (function() { return { BaseClass: function(){ this.someBaseProperty = "someBaseProperty"; this.someProperty = "BaseClass"; this.someFunc = null; }, DerivedClass:function(someFunc){ myNamespace.BaseClass.apply(this, arguments); this.someFunc = someFunc; this.someProperty = "DerivedClass"; }, MoreDerivedClass:function(someFunc){ myNamespace.DerivedClass.apply(this, arguments); this.someFunc = someFunc; this.someProperty = "MoreDerivedClass"; } }; })(); 

Da ES2015, è esattamente come si fa l’ereditarietà in JavaScript

 class Sub extends Base { } 
  1. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes
  2. http://exploringjs.com/es6/ch_classs.html
 function Base() { this.doSomething = function () { } } function Sub() { Base.call(this); // inherit Base's method(s) to this instance of Sub } var sub = new Sub(); sub.doSomething(); 

Non puoi ereditare da una class in JavaScript, perché non ci sono classi in JavaScript.

Classi ES6:

Javascript non ha classi. Le classi in javascript sono solo la generazione sintetica dello zucchero in cima al modello di ereditarietà prototipo che javascript. È ansible utilizzare la class JS per forzare l’ereditarietà del prototipo, ma è importante rendersi conto che si stanno ancora utilizzando le funzioni del costruttore.

Questi concetti si applicano anche quando si estende da una ‘class’ es6 usando la parola chiave extends. Questo crea solo un collegamento aggiuntivo nella catena del prototipo. Il __proto__

Esempio:

 class Animal { makeSound () { console.log('animalSound'); } } class Dog extends Animal { makeSound () { console.log('Woof'); } } console.log(typeof Dog) // classs in JS are just constructor functions under the hood const dog = new Dog(); console.log(dog.__proto__ === Dog.prototype); // First link in the prototype chain is Dog.prototype console.log(dog.__proto__.__proto__ === Animal.prototype); // Second link in the prototype chain is Animal.prototype // The extends keyword places Animal in the prototype chain // Now Dog 'inherits' the makeSound property from Animal