JavaScript-Vererbung [geschlossen]

80

Ich versuche, die Vererbung in Javascript zu implementieren. Ich habe mir den folgenden minimalen Code ausgedacht, um ihn zu unterstützen.

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

Experten, lassen Sie mich bitte wissen, ob dies ausreicht oder ein anderes wichtiges Problem, das ich möglicherweise übersehen habe. Aufgrund ähnlicher Probleme schlagen Sie bitte andere Änderungen vor.

Hier ist das vollständige Testskript:

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
    this.superalert = function(){
        alert('tst');
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

function Child(){
    Base.extend(this, Base);
    this.width = 20;
    this.height = 15;
    this.a = ['s',''];
    this.alert = function(){
        alert(this.a.length);
        alert(this.height);
    }
}

function Child1(){
    Base.extend(this, Child);
    this.depth = 'depth';
    this.height = 'h';
    this.alert = function(){
        alert(this.height); // display current object height
        alert(this.a.length); // display parents array length
        this.call(this.base.alert); 
          // explicit call to parent alert with current objects value
        this.call(this.base.superalert); 
          // explicit call to grandparent, parent does not have method 
        this.base.alert(); // call parent without overriding values
    }
}

var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);
hungrigMind
quelle
Wenn Sie eine Vererbung benötigen, gibt es viele, viele Bibliotheken, die dies bereits anbieten. Lesen Sie sie zumindest, um herauszufinden, wo Ihr Code falsch ist. Aber warum neu erfinden? Zwei fantastische Javascript-Vererbungsbibliotheken, die mir in den Sinn kommen, sind klass und selfish.js (ich habe beide verwendet, sie sind erstaunlich.)
bejonbee
Ich habe Klass verwendet, aber es gibt ein Problem beim Überschreiben von Array-Variablen. Ich werde es egoistisch versuchen. Aber meine Version ist einfacher 4-Zeilen-Code, funktioniert aber in den meisten Szenarien für mich. Ich möchte nur wissen, ob ich später mit diesem Ansatz nicht weiterkomme.
hungrigMind
2
Möglicherweise möchten Sie diese SO-Antwort auf eine ähnliche Frage überprüfen . Unter all den tollen Tipps zeigt der Autor, wie der Aufruf des Konstruktors des Elternteils beim Definieren der untergeordneten Klasse entfernt wird.
Bejonbee
@hungryMind: Wenn Sie sich Sorgen über bestimmte Probleme mit Ihrem Code machen, warum bearbeiten Sie Ihre Frage nicht und sagen Sie uns genau, wovor Sie Angst haben. Denn da Sie nur fragen, ob Ihr Code in Ordnung ist, wird er nicht viel gerecht. Sie werden wahrscheinlich keine Antworten bekommen, nach denen Sie suchen. Deshalb schlage ich vor, dass Sie Ihr Q.
Robert Koritnik
Diese Frage ist über das gleiche Thema: stackoverflow.com/questions/711209/…
Anderson Green

Antworten:

139

Um die Javascript-Vererbung in ECMAScript 5 zu implementieren , können Sie den Prototyp eines Objekts definieren und Object.createzum Erben verwenden. Sie können Eigenschaften auch beliebig hinzufügen / überschreiben.

Beispiel:

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.x = x;
    this.y = y;
}

// Inheritance
Translation.prototype = Object.create(Transform.prototype);

// Override
Translation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.angle = angle;
}

// Inheritance
Rotation.prototype = Object.create(Transform.prototype);

// Override
Rotation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15
Lorenzo Polidori
quelle
2
Translation.prototype = Object.create (neue Transformation ()); ? Translation.prototype = Object.create (Transform.prototype);
4esn0k
@ 4esn0k das stimmt, danke.
Lorenzo Polidori
Warum nicht einfach Translation.prototype = new Transform()? Würden Sie die Antwort bearbeiten, da sie derzeit nicht funktioniert?
Jörn Zaefferer
@ JörnZaefferer Schauen Sie hier: stackoverflow.com/q/4166616/885464 . Und was meinst du mit "Die Antwort funktioniert derzeit nicht"?
Lorenzo Polidori
4
Sie sollten den Konstruktor der Unterklasse auch explizit festlegen : Translation.prototype.constructor = Translation. Nützlich zum Klonen des Objekts (in den meisten Techniken).
Barboaz
41

Ich denke, Crockfords Lösung ist zu kompliziert, genau wie Johns. Es ist viel einfacher, eine Javascript-Vererbung zu erhalten, als beide zu beschreiben scheinen. Erwägen:

//Classes
function A() {
    B.call(this);
}

function B() {
    C.call(this);
    this.bbb = function() {
        console.log("i was inherited from b!");
    }
}

function C() {
    D.call(this);
}

function D() {
    E.call(this);
}

function E() {
    //instance property 
    this.id = Math.random()
}

//set up the inheritance chain (order matters) 
D.prototype = new E();
C.prototype = new D();
B.prototype = new C();
A.prototype = new B();

//Add custom functions to each
A.prototype.foo = function() {
    console.log("a");
};
B.prototype.bar = function() {
    console.log("b");
};
C.prototype.baz = function() {
    console.log("c");
};
D.prototype.wee = function() {
    console.log("d");
};
E.prototype.woo = function() {
    console.log("e");
};

//Some tests
a = new A();
a.foo();
a.bar();
a.baz();
a.wee();
a.woo();
console.log(a.id);
a.bbb();
console.log(a instanceof A);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(a instanceof D);
console.log(a instanceof E);​
var b = new B();
console.log(b.id)

Ich habe eine vollständige Beschreibung der oben genannten Lösung in meinem Blog geschrieben .

Marcosc
quelle
1
Außer dass es nur alle öffentlichen Mitglieder unterstützt
rodrigo-silveira
@ Rodrigo-Silveira, nicht sicher, was du meinst. Wenn Sie Privaten wollen, deklarieren Sie sie einfach mit var x = "was auch immer", nein?
Marcosc
2
Ich denke, @ rodrigo-silveira bedeutete, dass es keine geschützten Mitglieder unterstützt, und auch keine Lösung. (Auf private Mitglieder kann per Definition nicht über die Unterklasse zugegriffen werden, sodass dies keinen Sinn ergibt.) Sie müssen so etwas wie verwenden this._myProtectedVariable = 5;, um geschützte Mitglieder zu erstellen.
Ciantic
10
sehr schöne Lösung, nur (kleiner) Nachteil, die Konstruktoren werden zweimal ausgeführt. Einmal D.call (dies) und noch einmal: neues D (). Dies ist normalerweise kein großes Problem, aber wenn Sie es vermeiden möchten, können Sie Object.create folgendermaßen verwenden: anstelle von C.prototype = new D (); Sie können schreiben C.prototype = Object.create (D.prototype); Beispiel: jsfiddle.net/9Dxkb/1
Ray Hulha
1
Endlich eine nicht verwirrende Erklärung, die funktioniert! Ich habe Ihre Logik umgekehrt, um E in umgekehrter Richtung erben zu lassen (E hat am meisten zu bieten), da dies für mich Sinn machte. Vielen Dank!
Ed Bayiates
12

Während ich mit JS-Objekten spielte, fand ich eine minimalistischere Lösung :-) Viel Spaß!

function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }

Beispiel

function A() {
    this.info1 = function() {
        alert("A");
    }
}

function B(p1,p2) {
    extend(B,A,this);
    this.info2 = function() {
        alert("B"+p1+p2);
    }
}

function C(p) {
    extend(C,B,this,["1","2"]);
    this.info3 = function() {
        alert("C"+p);
    }
}


var c = new C("c");
c.info1(); // A
c.info2(); // B12
c.info3(); // Cc
Jan Turoň
quelle
8

Hier ist der einfachste und ich hoffe, der einfachste Weg, die Vererbung in JS zu verstehen. Am hilfreichsten ist dieses Beispiel für PHP-Programmierer.

function Mother(){
    this.canSwim = function(){
        console.log('yes');
    }
}

function Son(){};
Son.prototype = new Mother;
Son.prototype.canRun = function(){
    console.log('yes');
}

Jetzt hat der Sohn eine überschriebene Methode und eine neue

function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
    console.log('yes');
};
Grandson.prototype.canSwim = function(){
    console.log('no');
}

Jetzt hat der Enkel zwei überschriebene Methoden und eine neue

var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no
Alexander Serkin
quelle
Sicher ist es möglich, als Object.create (neuer Sohn)
Alexander Serkin
Das wäre noch schlimmer.
Bergi
4

Warum nicht Objekte anstelle von Funktionen verwenden:

var Base = {
    superalert : function() {
        alert('tst');
    }
};

var Child = Object.create(Base);
Child.width = 20;
Child.height = 15;
Child.a = ['s',''];
Child.childAlert = function () {
        alert(this.a.length);
        alert(this.height);
    }

var Child1 = Object.create(Child);
Child1.depth = 'depth';
Child1.height = 'h';
Child1.alert = function () {
    alert(this.height);
    alert(this.a.length);
    this.childAlert();
    this.superalert();
};

Und nenne es so:

var child1 = Object.create(Child1);
child1.alert();

Dieser Ansatz ist viel sauberer als bei Funktionen. Ich fand diesen Blog, in dem erklärt wurde, warum die Vererbung mit Funktionen in JS nicht richtig ist: http://davidwalsh.name/javascript-objects-deconstruction

BEARBEITEN

var Child kann auch geschrieben werden als:

var Child = Object.create(Base, {
    width : {value : 20},
    height  : {value : 15, writable: true},
    a : {value : ['s', ''], writable: true},
    childAlert : {value : function () {
        alert(this.a.length);
        alert(this.height);
    }}
});
Luka Blažecki
quelle
4

Hier ist meine Lösung, die auf der in Lorenzo Polidoris Antwort beschriebenen standardmäßigen prototypischen Vererbungsmethode basiert .

Zunächst definiere ich diese Hilfsmethoden, die die Dinge später verständlicher und lesbarer machen:

Function.prototype.setSuperclass = function(target) {
    // Set a custom field for keeping track of the object's 'superclass'.
    this._superclass = target;

    // Set the internal [[Prototype]] of instances of this object to a new object
    // which inherits from the superclass's prototype.
    this.prototype = Object.create(this._superclass.prototype);

    // Correct the constructor attribute of this class's prototype
    this.prototype.constructor = this;
};

Function.prototype.getSuperclass = function(target) {
    // Easy way of finding out what a class inherits from
    return this._superclass;
};

Function.prototype.callSuper = function(target, methodName, args) {
    // If methodName is ommitted, call the constructor.
    if (arguments.length < 3) {
        return this.callSuperConstructor(arguments[0], arguments[1]);
    }

    // `args` is an empty array by default.
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    var method = superclass.prototype[methodName];
    if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");

    return method.apply(target, args);
};

Function.prototype.callSuperConstructor = function(target, args) {
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    return superclass.apply(target, args);
};

Jetzt können Sie nicht nur die Oberklasse einer Klasse mit festlegen SubClass.setSuperclass(ParentClass), sondern auch überschriebene Methoden aufrufen mit SubClass.callSuper(this, 'functionName', [argument1, argument2...]):

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Translation.callSuper(this, arguments);

    // Public properties
    this.x = x;
    this.y = y;
}
// Inheritance
Translation.setSuperclass(Transform);

// Override
Translation.prototype.toString = function() {
    return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Rotation.callSuper(this, arguments);

    // Public properties
    this.angle = angle;
}
// Inheritance
Rotation.setSuperclass(Transform);

// Override
Rotation.prototype.toString = function() {
    return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

Zugegeben, selbst mit den Hilfsfunktionen ist die Syntax hier ziemlich umständlich. Zum Glück wurde in ECMAScript 6 etwas syntaktischer Zucker ( maximal minimale Klassen ) hinzugefügt, um die Dinge viel schöner zu machen. Z.B:

/**
 * Transform base class
 */
class Transform {
  constructor() {
    this.type = "2d";
  }

  toString() {
    return "Transform";
  } 
}

/**
 * Translation class.
 */
class Translation extends Transform {
  constructor(x, y) {
    super(); // Parent constructor

    // Public properties
    this.x = x;
    this.y = y;
  }

  toString() {
    return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
  }
}

/**
 * Rotation class.
 */
class Rotation extends Transform {
  constructor(angle) {
    // Parent constructor
    super(...arguments);

    // Public properties
    this.angle = angle;
  }

  toString() {
    return super(...arguments) + this.type + " Rotation " + this.angle;
  }
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

Beachten Sie, dass sich ECMAScript 6 zu diesem Zeitpunkt noch im Entwurfsstadium befindet und meines Wissens in keinem größeren Webbrowser implementiert ist. Wenn Sie möchten, können Sie jedoch den Traceur-Compiler verwenden , um ECMAScript 6das einfache ECMAScript 5JavaScript auf alter Basis zu kompilieren . Das obige Beispiel, das mit Traceur kompiliert wurde, finden Sie hier .

Ajedi32
quelle
2

Obwohl ich mit allen oben genannten Antworten einverstanden bin, bin ich der Meinung, dass JavaScript nicht objektorientiert sein muss (Vererbung vermeiden), sondern dass in den meisten Fällen ein objektbasierter Ansatz ausreichen sollte.

Ich mag die Art und Weise, wie Eloquent JavaScript sein Kapitel 8 über objektorientierte Programmierung beginnt und über OO spricht. Anstatt den besten Weg zur Implementierung der Vererbung zu entschlüsseln, sollte mehr Energie aufgewendet werden, um funktionale Aspekte von JavaScript zu lernen. Daher fand ich Kapitel 6 über funktionale Programmierung interessanter.

Anand
quelle
2
//This is an example of how to override a method, while preserving access to the original.
//The pattern used is actually quite simple using JavaScripts ability to define closures:

    this.somefunction = this.someFunction.override(function(args){
        var result = this.inherited(args);
        result += this.doSomethingElse();
        return result;
    });

//It is accomplished through this piece of code (courtesy of Poul Krogh):

/***************************************************************
    function.override overrides a defined method with a new one, 
    while preserving the old method.
    The old method is only accessible from the new one.
    Use this.inherited() to access the old method.
***************************************************************/

    Function.prototype.override = function(func)
    {
        var remember = this;
        var f = function() 
        {
             var save = this.inherited; 
             this.inherited = remember;
             var result = func.apply(this, Array.prototype.slice.call(arguments));
             this.inherited = save;
             return result;
        };
        return f;
    }
Lars Christensen
quelle
1

Wie wäre es mit diesem einfachen Ansatz

    function Body(){
        this.Eyes = 2;
        this.Arms = 2;
        this.Legs = 2;
        this.Heart = 1;
        this.Walk = function(){alert(this.FirstName + ' Is Walking')};
    }

    function BasePerson() {
        var BaseBody = new Body(this);
        BaseBody.FirstName = '';
        BaseBody.LastName = '';
        BaseBody.Email = '';
        BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
        return BaseBody;
    }

    function Person(FirstName,LastName)
    {
        var PersonBuild = new BasePerson();
        PersonBuild.FirstName = FirstName;
        PersonBuild.LastName = LastName;
        return PersonBuild;
    }

    var Person1 = new Person('Code', 'Master');
    Person1.IntroduceSelf();
    Person1.Walk();
CodeMilian
quelle
1

Grundlegende prototypische Vererbung

Eine einfache, aber effektive Methode zur Vererbung in JavaScript ist die Verwendung des folgenden Zweiliners:

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

Das ist ähnlich wie folgt:

B.prototype = new A();

Der Hauptunterschied zwischen beiden besteht darin, dass der Konstruktor von Abei Verwendung nicht ausgeführt wird Object.create, was intuitiver und der klassenbasierten Vererbung ähnlicher ist.

Sie können jederzeit festlegen, dass der Konstruktor von optional ausgeführt werden soll, Awenn Sie eine neue Instanz von erstellen B, indem Sie ihn dem Konstruktor hinzufügen von B:

function B(arg1, arg2) {
    A(arg1, arg2); // This is optional
}

Wenn Sie alle Argumente von Ban übergeben möchten A, können Sie auch Folgendes verwenden Function.prototype.apply():

function B() {
    A.apply(this, arguments); // This is optional
}

Wenn Sie ein anderes Objekt in den Konstruktor Kette mixin wollen B, können Sie kombinieren Object.createmit Object.assign:

B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;

Demo

function A(name) {
  this.name = name;
}

A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

function mixin() {

}

mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


Erstellen Sie Ihren eigenen Wrapper

Wenn Sie nicht gerne ungefähr denselben Zweizeiler in Ihren Code schreiben, können Sie eine grundlegende Wrapper-Funktion wie die folgende schreiben:

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

So funktioniert dieser Wrapper:

  1. Wenn Sie einen Parameter übergeben, erbt der Prototyp von Object.
  2. Wenn Sie zwei Parameter übergeben, erbt der Prototyp des ersten vom zweiten.
  3. Wenn Sie mehr als zwei Parameter übergeben, erbt der Prototyp des ersten vom zweiten und die Prototypen anderer Parameter werden eingemischt.

Demo

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

function A(name) {
  this.name = name;
}

inheritance(A);

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

inheritance(B, A);

function mixin() {

}

inheritance(mixin);

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

inheritance(C, B, mixin);

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


Hinweis

Object.createkann sicher in jedem modernen Browser verwendet werden, einschließlich IE9 +. Object.assignfunktioniert weder in einer IE-Version noch in einigen mobilen Browsern. Es wird empfohlen, Polyfill Object.create und / oder Object.assignwenn Sie sie verwenden und Browser unterstützen möchten, die sie nicht implementieren.

Eine Polyfüllung finden Sie Object.create hier und eine Object.assign hier .

John Slegers
quelle
0
//
//  try this one:
//  
//    function ParentConstructor() {}
//    function ChildConstructor()  {}
//
//    var 
//        SubClass = ChildConstructor.xtendz( ParentConstructor );
//
Function.prototype.xtendz = function ( SuperCtorFn ) {

    return ( function( Super, _slice ) {

                // 'freeze' host fn 
                var
                    baseFn = this, 
                    SubClassCtorFn;

                // define child ctor
                SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) {

                    // execute parent ctor fn on host object
                    // pass it last ( array ) argument as parameters
                    Super.apply( this, _slice.call( arguments, -1 )[0] );

                    // execute child ctor fn on host object
                    // pass remaining arguments as parameters
                    baseFn.apply( this, _slice.call( arguments, 0, -1 ) );

                };

                // establish proper prototype inheritance
                // 'inherit' methods
                SubClassCtorFn.prototype = new Super;

                // (re)establish child ctor ( instead of Super ctor )
                SubClassCtorFn.prototype.constructor = SubClassCtorFn;

                // return built ctor
                return SubClassCtorFn;

    } ).call( this, SuperCtorFn, Array.prototype.slice );
};

// declare parent ctor
function Sup( x1, x2 ) {
    this.parent_property_1 = x1;
    this.parent_property_2 = x2;
}

// define some methods on parent
Sup.prototype.hello = function(){ 
   alert(' ~  h e l l o   t h e r e  ~ ');
};


// declare child ctor
function Sub( x1, x2 ) {
    this.child_property_1 = x1;
    this.child_property_2 = x2;
}

var
    SubClass = Sub.xtendz(Sup), // get 'child class' ctor
    obj;

// reserve last array argument for parent ctor
obj = new SubClass( 97, 98, [99, 100] ); 

obj.hello();

console.log( obj );
console.log('obj instanceof SubClass      -> ', obj instanceof SubClass      );
console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass );
console.log('obj instanceof Sup           -> ', obj instanceof Sup           );
console.log('obj instanceof Object        -> ', obj instanceof Object        );

//
//  Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98}
//  obj instanceof SubClass      -> true
//  obj.constructor === SubClass -> true
//  obj instanceof Sup           -> true
//  obj instanceof Object        -> true
//
öffentliche Außerkraftsetzung
quelle
-1

Der einfachste Weg, die AWeb-Bibliothek zu verwenden . Offizielles Beispiel:

   /**
     * A-class
     */
   var ClassA = AWeb.class({
     public : {
        /**
          * A-class constructor
          */
        constructor : function() {
           /* Private variable */
           this.variable1 = "A";
           this.calls = 0;
        },

        /**
          * Function returns information about the object
          */
        getInfo : function() {
           this.incCalls();

           return "name=" + this.variable1 + ", calls=" + this.calls;
        }
     },
     private : {
        /**
          * Private function
          */
        incCalls : function() {
           this.calls++;
        }
     }
  });
  /**
    * B-class
    */
  var ClassB = AWeb.class({
     extends : ClassA,
     public : {
        /**
          * B-class constructor
          */
        constructor : function() {
           this.super();

           /* Private variable */
           this.variable1 = "B";
        },

        /**
          * Function returns extended information about the object
          */
        getLongInfo : function() {
           return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
        }
     }
  });
  /**
    * Main project function
    */
  function main() {
     var a = new ClassA(),
         b = new ClassB();

     alert(
        "a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
        "a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
        "b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo()=" + b.getInfo() + "\n" +
        "b.getLongInfo()=" + b.getLongInfo()
     );
  }
WebUser
quelle
-1

Ich fand eine Lösung viel einfacher als Dinge zu erweitern und Prototypen zu erstellen. Eigentlich weiß ich nicht, wie effizient das ist, obwohl es sauber und funktional aussieht.

var A = function (p) {
    if (p == null) p = this;
    p.a1 = 0;
    this.a2 = 0;
    var a3 = 0;
};

var B = function (p) {
    if (p == null) p = this;
    p.b1 = new A(this);
    this.b2 = new A(this);
    var b3 = new A(this);
    this b4 = new A();
};

var a = new A ();
var b = new B ();

Ergebnis:

a
    a1        0
    a2        0
b
    a1        0
    b1
        a2    0
    b2
        a2    0
    b4
        a1    0
        a2    0

praktisches Beispiel:

var Point = function (p) {
    if (p == null) p = this;
    var x = 0;
    var y = 0;
    p.getPoint = function () { return [x,y]; };
    p.setPoint = function (_x,_y) { x = _x; y = _y; };
};

var Dimension = function (p) {
    if (p == null) p = this;
    var w = 0;
    var h = 0;
    p.getDimension = function() { return [w,h] };
    p.setDimension = function(_w,_h) { w = _w; h = _h };
};

var Rect = function (p) {
    if (p == null) p = this;
    var dimension = new Dimension(this);
    var location  = new Point(this);
};

var rect = new Rect ();
rect.setDimension({w:30,h:40});
rect.setPoint({x:50,y:50});
Mortain
quelle