81

I am trying to implement inheritance in javascript. I came up with following minimal code to support it.

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

Experts, please let me know if this will be sufficient or any other important issue I may have missed. Based on similar issues faced please suggest other changes.

Here is complete test script:

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);
John Slegers
  • 45,213
  • 22
  • 199
  • 169
hungryMind
  • 6,931
  • 4
  • 29
  • 45
  • 2
    You might want to review [this SO answer to a similar question](http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript#1598077); among all the great tips the author shows how to remove the call to the parent's constructor when defining the child class. – Jonathan Beebe Sep 20 '11 at 15:09
  • This question is about the same topic: http://stackoverflow.com/questions/711209/which-javascript-library-has-the-most-comprehensive-class-inheritance-support – Anderson Green Feb 24 '13 at 07:06
  • Use Object.create() to innherit the base class prototype. http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon Jul 11 '13 at 13:49
  • Consider for a minute that JavaScript isn't statically type checked. To have several objects t aht implement a common interface, you just write objects that "implement" the interface, without ever even defining the interface. – bobobobo Jan 23 '14 at 01:59
  • If you need inheritance there are many, many libraries already offering this. At the very least read them to find out where you code is wrong. But why reinvent? Two awesome javascript inheritance libraries that come to mind are [klass](https://github.com/ded/klass) and [selfish.js](https://github.com/Gozala/selfish) (I've used both, they're amazing.) – Jonathan Beebe Sep 20 '11 at 14:41
  • I have used Klass but there is some problem in overriding array variables. I will try selfish. But my version is simple 4 line code, but works for me in most of the scenario. I just want to know if I will be stuck later with this approach. – hungryMind Sep 20 '11 at 14:47
  • @hungryMind: If you're worried about particular issues regarding your code, why don't you edit your question and tell us exactly what you're afraid of. Because since you're just asking whether your code is ok, doesn't give it much justice. You probably won't get answers you're looking for. Therefore I suggest you edit your Q. – Robert Koritnik Sep 20 '11 at 15:52
  • Do either of these libraries support multiple inheritance? – Anderson Green Feb 24 '13 at 07:08
  • @AndersonGreen - I don't think either of them support multiple inheritance. – Jonathan Beebe Feb 25 '13 at 15:43
  • Selfish.js supports multiple inheritance. – Design by Adrian Jan 09 '14 at 14:49

13 Answers13

141

To implement javascript inheritance in ECMAScript 5 you can define the prototype of an object and use Object.create to inherit. You can also add/override properties as much as you want.

Example:

/**
 * 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
  • 10,332
  • 10
  • 51
  • 60
  • 2
    Translation.prototype = Object.create(new Transform()); ? Translation.prototype = Object.create(Transform.prototype); – 4esn0k Oct 21 '12 at 03:34
  • Why not just `Translation.prototype = new Transform()`? Also, since the answer is currently not working, would you edit it? – Jörn Zaefferer Apr 11 '13 at 14:38
  • @JörnZaefferer Have a look here: http://stackoverflow.com/q/4166616/885464. And what do you mean with 'the answer is currently not working'? – Lorenzo Polidori Apr 11 '13 at 16:06
  • @JörnZaefferer Another interesting reading about the difference between [`Object.create`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create) and `new` is [here](http://stackoverflow.com/questions/2709612/using-object-create-instead-of-new?rq=1). Of course, as I specified in my answer, `Object.create` is available only in browsers that support ECMAScript5, so IE8 and below do not support it natively. But, just to make it clear, my example is a _perfectly working and widely used solution_ in ECMAScript5. – Lorenzo Polidori Apr 13 '13 at 08:19
  • Using this approach, is it possible for an function to call the parent function which it overrides? In other words, can we still access the overridden function somehow from the child? (Eg. In c# you would do something like base.someFunction() ) – UpTheCreek Jan 31 '14 at 05:21
  • @UpTheCreek Yes, of course you can. This is what `Translation.prototype.toString()` does in my example, calling `Transform.prototype.toString()`. With a plain javascript approach you need to know the exact name of the base function, i.e. you can't call a generic `base.toString()`. – Lorenzo Polidori Jan 31 '14 at 12:51
  • Ah yes, sorry missed that. – UpTheCreek Jan 31 '14 at 15:53
  • 4
    You should also set the constructor of the subclass explicitly: `Translation.prototype.constructor = Translation`. Useful for cloning the object (in most techniques). – barboaz Jun 09 '14 at 19:28
41

I think Crockfords solution is too complicated, as is John's. It's much simpler to get javascript inheritance than both of them seem to describe. Consider:

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

I've written a complete description of the above solution on my blog.

Marcosc
  • 3,101
  • 4
  • 17
  • 16
  • 1
    Except that it only supports all public members – rodrigo-silveira Oct 24 '12 at 17:11
  • @rodrigo-silveira, not sure what you mean. If you want privates, you just declare them with var x = "whatever", no? – Marcosc Nov 05 '12 at 23:50
  • 2
    I think @rodrigo-silveira meant that it does not support protected members, well neither solution does. (Private members by definition are not accessible from subclass so that would not make sense). You have to use something like `this._myProtectedVariable = 5;` to create protected members. – Ciantic Nov 21 '12 at 14:02
  • 10
    very nice solution, only (slight) drawback, the constructors are executed twice. Once D.call(this), and again: new D(). This usually is no big problem, but if you do want to avoid it, you can use Object.create like this: instead of C.prototype = new D(); you can write C.prototype = Object.create(D.prototype); example: http://jsfiddle.net/9Dxkb/1/ – Ray Hulha Jan 29 '13 at 23:25
  • 1
    Finally, a NON-CONFUSING explanation that works! I reversed your logic to make E inherit in the reverse direction (E has the most to it) as that made sense to me. Thanks! – Ed Bayiates Jul 19 '13 at 18:40
  • Actually Rya Hulha is correct, Mozilla defines inheritance as `var p = Object.create(o); // p is an object that inherits from o` yet somehow many people seems to use the `new` keyword instead... See this answer: http://stackoverflow.com/questions/4166616/understanding-the-difference-between-object-create-and-new-somefunction-in-j#answer-4166723 – Alexis Wilke Apr 05 '14 at 21:23
  • Actually, a better answer is the following, explaining that the `Object.create()` function does NOT call the constructor which makes sense when you are building a chained of prototypes. http://stackoverflow.com/questions/4166616/understanding-the-difference-between-object-create-and-new-somefunction-in-j#answer-14593952 – Alexis Wilke Apr 05 '14 at 21:33
  • "D.prototype = E;" is better than "D.prototype = new E();" ? (so the constructor of "E" is not called when you set up the inheritance.) – marirena Oct 15 '16 at 19:31
12

As I played with JS objects, I found a more minimalistic solution :-) Enjoy!

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

Example

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ň
  • 31,451
  • 23
  • 125
  • 169
8

Here is the simplest and I hope the easiest way to understand inheritance in JS. Most helpful this example will be for PHP programmers.

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

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

Now the son has one overridden method and one new

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

Now the grandson has two overridden methods and one new

var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no
Alexander Serkin
  • 1,679
  • 1
  • 12
  • 11
4

Why not use objects instead of functions :

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

And call it like this :

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

This approach is much more cleaner then with functions. I found this blog explaining why inheritance with functions isn't a proper way to do it in JS : http://davidwalsh.name/javascript-objects-deconstruction

EDIT

var Child can also be written as :

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
  • 183
  • 1
  • 7
4

Here's my solution, which is based on the standard prototypical inheritance method described in Lorenzo Polidori's answer.

First, I start off by defining these helper methods, which make things easier to understand and more readable later on:

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

Now, not only can you set the superclass of a class with SubClass.setSuperclass(ParentClass), but you can also call overridden methods with 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

Admittedly, even with the helper functions the syntax here is pretty awkward. Thankfully though, in ECMAScript 6 some syntactic sugar (maximally minimal classes) has been added to make things much prettier. E.g.:

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

Note that ECMAScript 6 is still in the draft stage at this point, and as far as I know is not implemented in any major web browser. However, if you wish you can use something like Traceur compiler to compile ECMAScript 6 down to the plain old ECMAScript 5-based JavaScript. You can see the above example compiled using Traceur here.

Community
  • 1
  • 1
Ajedi32
  • 45,670
  • 22
  • 127
  • 172
2

While I agree with all above answers, I feel that JavaScript need not be Object Oriented, (Avoid inheritance), instead an object-based approach should be sufficient in most cases.

I like the way Eloquent JavaScript starts its Chapter 8 on Object Oriented Programming talking about OO. Instead of deciphering best way to implement Inheritance, more energy should be devoted to learn functional aspects of JavaScript, hence, I found Chapter 6 on Functional Programming, more interesting.

Community
  • 1
  • 1
Anand
  • 4,523
  • 10
  • 47
  • 72
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;
    }
Josh Lee
  • 171,072
  • 38
  • 269
  • 275
2

Basic prototypical inheritance

A simple but effective way to do inheritance in JavaScript, is to use the following two-liner :

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

That is similar to doing this :

B.prototype = new A();

The main difference between both is that the constructor of A is not run when using Object.create, which is more intuitive and more similar to class based inheritance.

You can always choose to optionally run the constructor of A when creating a new instance of B by adding adding it to the constructor of B :

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

If you want to pass all arguments of B to A, you can also use Function.prototype.apply() :

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

If you want to mixin another object into the constructor chain of B, you can combine Object.create with 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());

Creating your own wrapper

If you don't like writing roughly the same two-liner throughout your code, you could write a basic wrapper function like this :

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

How this wrapper works :

  1. If you pass a one parameter, it's prototype will inherit from Object.
  2. If you pass two parameters, the first's prototype will inherit from the second's.
  3. If you pass more than two parameters, the first's prototype will inherit from the second's and the prototypes of other parameters will be mixed in.

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

Note

Object.create can be safely used in every modern browser, including IE9+. Object.assign does not work in any version of IE nor some mobile browsers. It is recommended to polyfill Object.create and/or Object.assign if you want to use them and support browsers that do not implement them.

You can find a polyfill for Object.create here and one for Object.assign here.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
1

How about this simple approach

    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
  • 1,262
  • 2
  • 17
  • 41
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
//
public override
  • 974
  • 8
  • 17
-1

The easiest way to use AWeb library. Official sample:

   /**
     * 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()
     );
  }
-1

I found a solution much easier than extend and prototyping things. Actually I don't know how efficient this is though it looks clean and functional.

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

result:

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

practical example:

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
  • 3
  • 3