webentwicklung-frage-antwort-db.com.de

Wie von einer Klasse in Javascript erben?

In PHP/Java kann man folgendes tun:

class Sub extends Base
{
}

Und automatisch werden alle öffentlichen/geschützten Methoden, Eigenschaften, Felder usw. der Superklasse Teil der Subklasse, die bei Bedarf überschrieben werden kann.

Was ist das Äquivalent dazu in Javascript?

94
Click Upvote

Ich habe geändert, wie ich das jetzt mache. Ich versuche, Konstruktorfunktionen und deren prototype -Eigenschaft zu vermeiden, aber meine alte Antwort aus 2010 ist immer noch ganz unten. Ich bevorzuge jetzt Object.create(). Object.create ist in allen modernen Browsern verfügbar.

Ich sollte beachten, dass Object.create normalerweise viel langsamer ist als new mit einem Funktionskonstruktor.

//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

Einer der großen Vorteile der Verwendung von Object.create besteht in der Möglichkeit, ein Argument defineProperties zu übergeben, mit dem Sie maßgeblich steuern können, wie auf die Eigenschaften der Klasse zugegriffen werden kann, und ich benutze Funktionen zum Erstellen von Instanzen Diese dienen in gewisser Weise als Konstruktoren, da Sie am Ende eine Initialisierung durchführen können, anstatt nur die Instanz zurückzugeben.

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

Dies ist meine ursprüngliche Antwort aus 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"
78
Bjorn Tipling

In JavaScript haben Sie nicht classes, aber Sie können Vererbung und Verhalten auf verschiedene Weise wiederverwenden:

Pseudoklassische Vererbung (durch Prototyping):

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

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

Sollte mit dem Operator new verwendet werden:

var subInstance = new Sub();

Funktionsanwendung oder "Konstruktorketten":

function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


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

Dieser Ansatz sollte auch mit dem Operator new verwendet werden:

var subInstance = new Sub();

Der Unterschied zum ersten Beispiel besteht darin, dass wenn wir apply den Konstruktor Super dem Objekt this in Sub hinzufügen, die Eigenschaften hinzugefügt werden, die this auf Super direkt in der neuen Instanz zugewiesen sind, z. subInstance enthält die Eigenschaften member1 und member2 direkt (subInstance.hasOwnProperty('member1') == true;).

Im ersten Beispiel werden diese Eigenschaften durch das Prototypkette erreicht, sie sind in einem internen [[Prototype]]-Objekt vorhanden.

Parasitäre Vererbung oder Power Constructors:

function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}

Dieser Ansatz basiert im Wesentlichen auf "Objekterweiterung". Sie müssen den Operator new nicht verwenden. Wie Sie sehen, ist das Schlüsselwort this nicht beteiligt.

var subInstance = createSub();

ECMAScript 5. Auflage. Object.create methode:

// 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';

Das obige Verfahren ist eine prototypische Vererbungstechnik, die von Crockford vorgeschlagen wird.

Objektinstanzen erben von anderen Objektinstanzen, das ist es.

Diese Technik kann besser als eine einfache "Objekterweiterung" sein, da die geerbten Eigenschaften nicht über alle neuen Objektinstanzen kopiert werden, da das base-Objekt als [[Prototype]] des extended festgelegt ist. Im obigen Beispiel enthält subInstance physisch nur die member3-Eigenschaft.

186
CMS

Für diejenigen, die diese Seite 2015 oder danach erreichen

Mit der neuesten Version des ECMAScript-Standards (ES6) können Sie de keywork extends verwenden.

Beachten Sie, dass die Klassendefinition keine reguläre object ist. Daher gibt es keine Kommas zwischen den Klassenmitgliedern. Um eine Instanz einer Klasse zu erstellen, müssen Sie das Schlüsselwort new verwenden. Um von einer Basisklasse zu erben, verwenden Sie 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'

Um von einer Basisklasse zu erben, verwenden Sie 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

Von der abgeleiteten Klasse aus können Sie super von jedem Konstruktor oder von jeder Methode verwenden, um auf seine Basisklasse zuzugreifen:

  • Um den übergeordneten Konstruktor aufzurufen, verwenden Sie super().
  • Um ein anderes Mitglied anzurufen, verwenden Sie zum Beispiel super.getName().

Es gibt mehr zur Verwendung von Klassen. Wenn Sie tiefer in das Thema eintauchen möchten, empfehle ich „ Klassen in ECMAScript 6 “ von Dr. Axel Rauschmayer. *

Quelle

42
Merlin

In JavaScript gibt es keine "Klassenvererbung", sondern nur "Prototypvererbung". Sie machen also keine Klasse "Lastwagen" und markieren sie dann als Unterklasse von "Automobil". Stattdessen erstellen Sie ein Objekt "Jack" und sagen, dass es "John" als Prototyp verwendet. Wenn John weiß, wie viel "4 + 4" ist, weiß Jack es auch. 

Ich schlage vor, dass Sie Douglas Crockfords Artikel über die Vererbung von Prototypen hier lesen: http://javascript.crockford.com/prototypal.html Er zeigt auch, wie Sie JavaScript wie in anderen OO sprachen und erklärt dann, dass dies tatsächlich bedeutet, JavaScript auf eine Weise zu brechen, die es nicht verwenden sollte.

7
naivists

Ich finde dieses Zitat am aufschlussreichsten:

Im Wesentlichen ist ein JavaScript "class" nur ein Function-Objekt, das als Konstruktor plus angefügtes Prototypobjekt dient. ( Quelle: Guru Katz )

Ich benutze lieber Konstruktoren als Objekte, daher bin ich Teil der Methode "pseudo-klassische Vererbung" hier beschrieben von CMS . Hier ist ein Beispiel für multiple Vererbung mit einer Prototypkette:

// 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 "classes"

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 "classes" 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

Hier ist eine weitere gute Ressource von MDN , und hier ist eine jsfiddle, so dass Sie es ausprobieren können .

6
Luke

Die JavaScript-Vererbung unterscheidet sich ein wenig von Java und PHP, da sie nicht wirklich über Klassen verfügt. Stattdessen gibt es Prototypobjekte, die Methoden und Membervariablen bereitstellen. Sie können diese Prototypen verketten, um Objektvererbung bereitzustellen. Das häufigste Muster, das ich bei der Erforschung dieser Frage gefunden habe, wird im Mozilla Developer Network beschrieben. Ihr Beispiel wurde aktualisiert, um einen Aufruf einer Superklassenmethode einzuschließen und das Protokoll in einer Warnmeldung anzuzeigen:

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

Ich persönlich finde Vererbung in Javascript unangenehm, aber dies ist die beste Version, die ich gefunden habe.

4
Don Kirkby

sie können nicht (im klassischen Sinne). Javascript ist eine prototypische Sprache. Sie werden feststellen, dass Sie niemals eine "Klasse" in Javascript deklarieren. Sie definieren lediglich den Zustand und die Methoden eines Objekts. Um Vererbung zu erzeugen, nehmen Sie ein Objekt und prototypisieren es. Der Prototyp wird um neue Funktionen erweitert. 

3
D.C.

Nachdem ich viele Beiträge gelesen hatte, kam ich zu dieser Lösung ( jsfiddle here ). Meistens brauche ich nichts anspruchsvolleres

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();
1
chauwel
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();
1
Kai Hartmann

Sie können .inheritWith und .fastClasslibrary verwenden. Es ist schneller als die meisten gängigen Bibliotheken und manchmal sogar schneller als die native Version.

Sehr einfach zu bedienen:

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

Verwendungszweck

var s = new Sub();
s.method1(); //prints:
//sub 
//super
1
Adaptabi
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
1
nnattawat

ES6 Klassen:

Javascript hat keine Klassen. Klassen in Javascript sind nur syntaktischer Zucker, der auf dem Muster prototypische Vererbung javascript aufgebaut ist. Sie können JS class verwenden, um die prototypische Vererbung zu erzwingen. Es ist jedoch wichtig zu wissen, dass Sie tatsächlich noch Konstruktorfunktionen unter der Haube verwenden.

Diese Konzepte gelten auch, wenn Sie von einer es6 - 'Klasse' mit dem extend-Schlüsselwort erweitern. Dies schafft nur ein zusätzliches Glied in der Prototypenkette. Der __proto__

Beispiel:

class Animal {
  makeSound () {
    console.log('animalSound');
  }
}

class Dog extends Animal {
   makeSound () {
    console.log('Woof');
  }
}


console.log(typeof Dog)  // classes 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

Object.create ()

Object.create() ist auch eine Möglichkeit, eine Vererbung in JS in Javascript zu erstellen. Object.create() ist eine Funktion, die ein neues Objekt erstellt und ein vorhandenes Objekt als Argument verwendet. Das Objekt, das als Argument empfangen wurde, wird der Eigenschaft __proto__ Des neu erstellten Objekts zugewiesen. Wieder ist es wichtig zu erkennen, dass wir an das prototypische Vererbungsparadigma gebunden sind, das JS verkörpert.

Beispiel:

const Dog = {
  fluffy: true,
  bark: () => {
      console.log('woof im a relatively cute dog or something else??');
  }
};

const dog = Object.create(Dog);

dog.bark();
1

Von ES2015 aus verfahren Sie genau so in JavaScript

class Sub extends Base {

}
  1. https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Classes
  2. http://exploringjs.com/es6/ch_classes.html
1
Boopathi Rajaa

Dank der Antwort von CMS und nachdem ich eine Weile mit prototype und Object.create gearbeitet hatte und was nicht, konnte ich eine ordentliche Lösung für meine Vererbung finden.

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";
        }
    };
})();
1
pasx

In JavaScript können Sie nicht von einer Klasse erben, da in JavaScript keine Klassen vorhanden sind.

0
Jörg W Mittag