webentwicklung-frage-antwort-db.com.de

JavaScript erweiternde Klasse

Ich habe eine Basisklasse:

function Monster() {
  this.health = 100;
}

Monster.prototype.growl = function() {
  console.log("Grr!");
}

Dass ich eine weitere Klasse erweitern und erstellen möchte mit:

function Monkey extends Monster() {
  this.bananaCount = 5;
}

Monkey.prototype.eatBanana {
  this.bananaCount--;
  this.health++; //Accessing variable from parent class monster
  this.growl();  //Accessing function from parent class monster
}

Ich habe ziemlich viel recherchiert und es scheint viele komplizierte Lösungen dafür in JavaScript zu geben. Was wäre der einfachste und zuverlässigste Weg, dies in JS zu erreichen?

64
Lucas Penney

Für ES6 unten aktualisiert

März 2013 und ES5

Dieses MDN-Dokument beschreibt die Erweiterung von Klassen.

https://developer.mozilla.org/en-US/docs/JavaScript/Einführung_zum_Objekt-Oriented_JavaScript

Im Einzelnen beschäftigen sie sich jetzt damit:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = Object.create(Person.prototype);

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

Beachten Sie, dass Object.create() in einigen älteren Browsern, einschließlich IE8, nicht unterstützt wird:

 Object.create browser support

Wenn Sie diese unterstützen müssen, schlägt das verknüpfte MDN-Dokument die Verwendung einer Polyfill oder der folgenden Näherung vor:

function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

Die Verwendung dieser Funktion wie Student.prototype = createObject(Person.prototype) ist der Verwendung von new Person() vorzuziehen, da sie den Aufruf der Konstruktorfunktion des übergeordneten Elements beim Erben des Prototyps vermeidet und den übergeordneten Konstruktor nur aufruft, wenn der Konstruktor des Vererbers aufgerufen wird.

Mai 2017 und ES6

Zum Glück haben die JavaScript-Designer unsere Hilferufe gehört und eine passendere Herangehensweise für dieses Problem gewählt.

MDN hat ein weiteres hervorragendes Beispiel für die Vererbung von ES6-Klassen, aber ich zeige genau die gleiche Klasse von Klassen wie oben in ES6 wiedergegeben:

class Person {
    sayHello() {
        alert('hello');
    }

    walk() {
        alert('I am walking!');
    }
}

class Student extends Person {
    sayGoodBye() {
        alert('goodBye');
    }

    sayHello() {
        alert('hi, I am a student');
    }
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

Sauber und verständlich, so wie wir es uns alle wünschen. Denken Sie daran, dass ES6 zwar häufig ist, aber nicht überall unterstützt wird :

 ES6 browser support

130
Oliver Spryn

ES6 gibt Ihnen jetzt die Möglichkeit, Klasse & Erweiterungen  

Dann lautet Ihr Code: 

Sie haben eine Basisklasse:

class Monster{
       constructor(){
             this.health = 100;
        }
       growl() {
           console.log("Grr!");
       }

}

Sie möchten eine weitere Klasse erweitern und erstellen mit:

class Monkey extends Monster {
        constructor(){
            super(); //don't forget "super"
            this.bananaCount = 5;
        }


        eatBanana() {
           this.bananaCount--;
           this.health++; //Accessing variable from parent class monster
           this.growl(); //Accessing function from parent class monster
        }

}
12
Abdennour TOUMI

Versuche dies:

Function.prototype.extends = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

Monkey.extends(Monster);
function Monkey() {
  Monster.apply(this, arguments); // call super
}

Edit: Ich habe hier eine kurze Demo http://jsbin.com/anekew/1/edit . Beachten Sie, dass extends ein reserviertes Word in JS ist und dass Sie beim Flusen Ihres Codes möglicherweise Warnungen erhalten. Sie können es einfach inherits nennen. Das mache ich normalerweise.

Wenn dieser Helfer vorhanden ist und ein Objekt props als einzigen Parameter verwendet wird, wird die Vererbung in JS etwas einfacher:

Function.prototype.inherits = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

function Monster(props) {
  this.health = props.health || 100;
}

Monster.prototype = {
  growl: function() {
    return 'Grrrrr';
  }
};

Monkey.inherits(Monster);
function Monkey() {
  Monster.apply(this, arguments);
}

var monkey = new Monkey({ health: 200 });

console.log(monkey.health); //=> 200
console.log(monkey.growl()); //=> "Grrrr"
10
elclanrs

Wenn Sie den Prototyp-Ansatz nicht mögen, weil er sich nicht wirklich wie ein Nice-OOP-Modus verhält, können Sie Folgendes versuchen:

var BaseClass = function() 
{
    this.some_var = "foobar";

    /**
     * @return string
     */
    this.someMethod = function() {
        return this.some_var;
    }
};

var MyClass = new Class({ extends: BaseClass }, function()
{
    /**
     * @param string value
     */
    this.__construct = function(value)
    {
        this.some_var = value;
    }
})

Verwenden der Lightweight-Bibliothek (2k minimiert): https://github.com/haroldiedema/joii

6
Harold

Dies ist eine Erweiterung (entschuldigen Sie das Wortspiel) der Lösung von elclanrs, um detailliertere Informationen zu Instanzmethoden aufzunehmen und einen erweiterbaren Ansatz für diesen Aspekt der Frage zu finden. Ich akzeptiere voll und ganz, dass dies dank David Flanagans "JavaScript: The Definitive Guide" (teilweise für diesen Kontext angepasst) zusammengestellt wurde. Beachten Sie, dass dies eindeutig ausführlicher ist als bei anderen Lösungen, dies würde jedoch langfristig wahrscheinlich von Vorteil sein.

Zuerst verwenden wir Davids einfache "extend" -Funktion, die Eigenschaften in ein angegebenes Objekt kopiert:

function extend(o,p) {
    for (var prop in p) {
        o[prop] = p[prop];
    }
    return o;
}

Dann implementieren wir sein Subclass-Definitionsdienstprogramm:

function defineSubclass(superclass,     // Constructor of our superclass
                          constructor,  // Constructor of our new subclass
                          methods,      // Instance methods
                          statics) {    // Class properties
        // Set up the prototype object of the subclass
    constructor.prototype = Object.create(superclass.prototype);
    constructor.prototype.constructor = constructor;
    if (methods) extend(constructor.prototype, methods);
    if (statics) extend(constructor, statics);
    return constructor;
}

Für die letzte Vorbereitung verbessern wir unseren Funktionsprototyp mit Davids neuer Jiggery-Pokery:

Function.prototype.extend = function(constructor, methods, statics) {
    return defineSubclass(this, constructor, methods, statics);
};

Nach der Definition unserer Monster-Klasse führen wir Folgendes aus (was für alle neuen Klassen, die wir erweitern/erben möchten, wiederverwendbar ist):

var Monkey = Monster.extend(
        // constructor
    function Monkey() {
        this.bananaCount = 5;
        Monster.apply(this, arguments);    // Superclass()
    },
        // methods added to prototype
    eatBanana: function() {
        this.bananaCount--;
        this.health++;
        this.growl();
    }
);
1
GMeister

Ich kann eine Variante vorschlagen, die ich gerade in einem Buch gelesen habe, es scheint die einfachste zu sein:

function Parent() { 
  this.name = 'default name';
};

function Child() {
  this.address = '11 street';
};

Child.prototype = new Parent();      // child class inherits from Parent
Child.prototype.constructor = Child; // constructor alignment

var a = new Child(); 

console.log(a.name);                // "default name" trying to reach property of inherited class
1
Yarik

Für die traditionelle Erweiterung können Sie einfach die Superklasse als Konstruktorfunktion Schreiben und diesen Konstruktor dann für Ihre geerbte Klasse anwenden.

     function AbstractClass() {
      this.superclass_method = function(message) {
          // do something
        };
     }

     function Child() {
         AbstractClass.apply(this);
         // Now Child will have superclass_method()
     }

Beispiel zu anglejs:

http://plnkr.co/edit/eFixlsgF3nJ1LeWUJKsd?p=preview

app.service('noisyThing', 
  ['notify',function(notify){
    this._constructor = function() {
      this.scream = function(message) {
          message = message + " by " + this.get_mouth();
          notify(message); 
          console.log(message);
        };

      this.get_mouth = function(){
        return 'abstract mouth';
      }
    }
  }])
  .service('cat',
  ['noisyThing', function(noisyThing){
    noisyThing._constructor.apply(this)
    this.meow = function() {
      this.scream('meooooow');
    }
    this.get_mouth = function(){
      return 'fluffy mouth';
    }
  }])
  .service('bird',
  ['noisyThing', function(noisyThing){
    noisyThing._constructor.apply(this)
    this.twit = function() {
      this.scream('fuuuuuuck');
    }
  }])
0
Dan Key

Für Autodidakten:

function BaseClass(toBePrivate){
    var morePrivates;
    this.isNotPrivate = 'I know';
    // add your stuff
}
var o = BaseClass.prototype;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';


// MiddleClass extends BaseClass
function MiddleClass(toBePrivate){
    BaseClass.call(this);
    // add your stuff
    var morePrivates;
    this.isNotPrivate = 'I know';
}
var o = MiddleClass.prototype = Object.create(BaseClass.prototype);
MiddleClass.prototype.constructor = MiddleClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';



// TopClass extends MiddleClass
function TopClass(toBePrivate){
    MiddleClass.call(this);
    // add your stuff
    var morePrivates;
    this.isNotPrivate = 'I know';
}
var o = TopClass.prototype = Object.create(MiddleClass.prototype);
TopClass.prototype.constructor = TopClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';


// to be continued...

Erstellen Sie eine Instanz mit Getter und Setter:

function doNotExtendMe(toBePrivate){
    var morePrivates;
    return {
        // add getters, setters and any stuff you want
    }
}
0
Steffomio

Zusammenfassung:

Es gibt mehrere Möglichkeiten, um das Problem der Erweiterung einer Konstruktorfunktion um einen Prototyp in Javascript zu lösen. Welche dieser Methoden ist die "beste" Lösung, ist meinungsbasiert. Es gibt jedoch zwei häufig verwendete Methoden, um den Funktionsprototyp eines Konstruktors zu erweitern.

ES 2015 Klassen:

class Monster {
  constructor(health) {
    this.health = health
  }
  
  growl () {
  console.log("Grr!");
  }
  
}


class Monkey extends Monster {
  constructor (health) {
    super(health) // call super to execute the constructor function of Monster 
    this.bananaCount = 5;
  }
}

const monkey = new Monkey(50);

console.log(typeof Monster);
console.log(monkey);

Der obige Ansatz, ES 2015-Klassen zu verwenden, ist nichts weiter als syntaktischer Zucker über das prototypische Vererbungsmuster in Javascript. Im ersten Protokoll, in dem wir typeof Monster auswerten, können wir feststellen, dass dies eine Funktion ist. Dies liegt daran, dass Klassen nur Konstruktorfunktionen unter der Haube sind. Trotzdem mögen Sie diese Art der Implementierung von prototypischer Vererbung mögen und sollten sie definitiv lernen. Es wird in wichtigen Frameworks wie ReactJS und Angular2+ verwendet.

Werksfunktion mit Object.create():

function makeMonkey (bananaCount) {
  
  // here we define the prototype
  const Monster = {
  health: 100,
  growl: function() {
  console.log("Grr!");}
  }
  
  const monkey = Object.create(Monster);
  monkey.bananaCount = bananaCount;

  return monkey;
}


const chimp = makeMonkey(30);

chimp.growl();
console.log(chimp.bananaCount);

Diese Methode verwendet die Object.create()-Methode, die ein Objekt übernimmt, das der Prototyp des neu erstellten Objekts ist, das es zurückgibt. Deshalb erstellen wir zuerst das Prototypobjekt in dieser Funktion und rufen dann Object.create() auf, das ein leeres Objekt mit der __proto__-Eigenschaft für das Monster-Objekt zurückgibt. Danach können wir alle Eigenschaften des Objekts initialisieren. In diesem Beispiel weisen wir dem neu erstellten Objekt den Banan-Account zu. 

0

die absolut minimale (und im Gegensatz zu vielen Antworten oben richtige) Version lautet:

function Monkey(param){
  this.someProperty = param;
}
Monkey.prototype = Object.create(Monster.prototype);
Monkey.prototype.eatBanana = function(banana){ banana.eat() }

Das ist alles. Sie können hier die längere Erklärung lesen

0
gdanov