Rectangle 27 1

javascript How to achieve pseudo classical inheritance right on the class declaration?


alert(Abc.isPrototypeOf(Xyz)); // true
alert(x.key + ": " + x.value + "; isAbc: " + Abc.isPrototypeOf(x));
alert(y.key + ": " + y.value + "; isAbc: " + Abc.isPrototypeOf(y));

alert(it.key + ": " + it.value + "; isAbc: " + Abc.isPrototypeOf(it));
alert(it.key + ": " + it.value + "; isXyz: " + Xyz.isPrototypeOf(it));
augment
extend
function ABC(key, value) {
    this.key = key;
    this.value = value;
}

ABC.prototype.what = function() {
    alert("what");
};
function CLASS(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}
function augment(body) {
    var base = typeof this === "function" ? this.prototype : this;
    var prototype = Object.create(base);
    body.apply(prototype, arrayFrom(arguments, 1).concat(base));
    if (!ownPropertyOf(prototype, "constructor")) return prototype;
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}
function extend(self, body) {
    var base = typeof self === "function" ? self.prototype : self;
    var prototype = Object.create(base, {new: {value: create}});
    return body.call(prototype, base), prototype;

    function create() {
        var self = Object.create(prototype);
        return prototype.hasOwnProperty("constructor") &&
            prototype.constructor.apply(self, arguments), self;
    }
}
instanceof
isPrototypeOf
var ABC = CLASS({
    constructor: function (key, value) {
        this.key = key;
        this.value = value;
    },
    what: function () {
        alert("what");
    }
});

function CLASS(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}
var Abc = extend(Object, function () {
    this.constructor = function (key, value) {
        this.value = 333 + Number(value);
        this.key = key;
    };

    this.what = function () {
        alert("what");
    };
});
var ClassA = extend(Object, function () {
    var ClassB = extend(this, function () {
        // class definition
    });

    // rest of the class definition

    alert(this.isPrototypeOf(ClassB)); // true
});
var Xyz = extend(Abc, function (base) {
    this.empty = this.new();

    this.constructor = function (key, value) {
        base.constructor.call(this, key, value);
    };

    this.that = function () {
        alert("that");
    };
});
var augment = require("augment");

var ABC = augment(Object, function () {
    this.constructor = function (key, value) {
        this.key = key;
        this.value = value;
    };

    this.what = function () {
        alert("what");
    };
});

var XYZ = augment(ABC, function (base) {
    this.constructor = function (key, value) {
        base.constructor.call(this, key, value);
    };

    this.that = function () {
        alert("that");
    };
});
var it = Abc.new.apply(null, ["it", "789"]);
var x = Xyz.new("x", "123");
var y = Xyz.new("y", "456");
var it = Abc.new("it", "789");
x.what();
y.that();

it.what();
it.that(); // will throw; it is not Xyz and does not have that method
  • Create a derived class prototype using Object.create.
  • Every constructor has a property called prototype which points to the prototype object of the constructor function.
  • Every prototype has a property called constructor which points to the constructor function of the prototype object.
  • Get the base class prototype.
  • Populate the derived class prototype with the specified properties.
  • We create an instance from a constructor function. However the instance actually inherits from the prototype, not the constructor.

@AaditMShah: Thanks for the update, but I cannot upvote twice :-). However, I don't really like your static properties, which are just prototype properties (and accessing them on the instances might trap some people into trying to assign them on the instances). I had more thought of something like in this answer of mine where there are two separate (cross-linked) prototype chains for the Class objects and the instances.

Another problem with augment that I cannot see a solution is to declare nesting classes which derive from the declaring class.

As you can see encapsulation is easy to achieve in JavaScript. All you need to do is think sideways. Inheritance however is a different issue. You need to do a little more work to achieve inheritance.

Besides this minor change everything else works just like it did before:

Every JavaScript programmer worth their salt will tell you that prototypal inheritance is better than classical inheritance. Nevertheless newbies who come from a language with classical inheritance always try to implement classical inheritance on top of prototypal inheritance, and they usually fail.

Finally, because the class is accessible from within the class definition as this, you can created nested classes which inherit from the class which they are nested within by using extend as follows:

However once you understand true prototypal inheritance you'll never want to go back to classical inheritance. I too tried to implement classical inheritance on top of prototypal inheritance as a newbie. Now that I understand how true prototypal inheritance works however I write code like this:

However using our newfound knowledge we may write the same thing as:

I don't know about you but to me this looks a lot like classical inheritance in C++ or Java. If this solves your problem, great! If is doesn't then continue reading.

If you want something similar to classes in JavaScript then there are a lot of libraries out there which provide it to you. For example using augment you could restructure your code as follows:

In a lot of ways prototypes are similar to classes. In fact prototypes and classes are so similar that we can use prototypes to model classes. First let's take a look at how prototypal inheritance really works:

In addition because Xyz is the prototype object we can access Xyz.empty directly (i.e. empty is a static property of Xyz). This also means that static properties are automatically inherited and are no different from normal properties.

Inheritance is just as simple:

Notice that the last three lines are the same as that of CLASS from the previous section:

Notice that we can create instances of the class from within the class itself by calling this.new. If this.constructor is not yet defined then it returns a new uninitialized instance. Otherwise it returns a new initialized instance.

Remember however that extend does not return the constructor function. It returns the prototype object. This means that you can't use the new keyword to create an instance of the class. Instead you need to use new as a method, as follows:

Since Abc and Xyz are not constructor functions we can't use instanceof to test whether an object is an instance of Abc or Xyz. However that's not a problem because JavaScript has a method called isPrototypeOf which tests whether an object is a prototype of another object:

That's all that there is to inheritance in JavaScript. If you want to create your own classical inheritance pattern then you should be thinking along the same lines.

The above extend function is very similar to augment. However instead of returning the constructor function it returns the prototype object. This is actually a very neat trick which allows static properties to be inherited. You can create a class using extend as follows:

The above picture was taken from the following answer. I suggest you read it carefully. The diagram shows us:

The first three lines of augment are used to:

There's a known issue that the properties like instance.What in fact are not inherited from the prototype and each instance has its own property, which can be solved by adding an argument and passing the prototype to the initialize function such as function (instance, prototype, _super); but that approach doesn't work with a closure captures the arguments of the constructor. I'm still reading your answer, and sorry for giving you migraines ..

They fail not because it's not possible to implement classical inheritance on top of prototypal inheritance but because to implement classical inheritance on top of prototypal inheritance you first need to understand how true prototypal inheritance works.

This is actually a good thing. The new keyword is considered harmful and I strongly recommend you to stop using it. For example it's not possible to use apply with the new keyword. However it is possible to use apply with the new method as follows:

This is very useful information. Traditionally we've always created a constructor function first and then we've set its prototype properties. However this information shows us that we may create a prototype object first and then define the constructor property on it instead.

This tells us that once we have a prototype object all we need to do is get its constructor property and return it.

What else does true prototypal inheritance offer? One of the biggest advantages of true prototypal inheritance is that there's no distinction between normal properties and static properties allowing you to write code like this:

augment seems a good solution but I'm wondering how to declare an instance of type which is being declared, such as declaring Xyz.Empty=new Xyz(); inside while Xyz is not yet declared, using this.constructor to do that may reduce the readability ..

Note
Rectangle 27 1

javascript How to achieve pseudo classical inheritance right on the class declaration?


var goog={};//inherits from closure library base
  //http://docs.closure-library.googlecode.com/git/closure_goog_base.js.source.html#line1466
  // with modifications for _super
goog.inherits = function(childCtor, parentCtor) {
  function tempCtor() {};
  tempCtor.prototype = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  childCtor.prototype.constructor = childCtor;
  // modified _super
  childCtor.prototype._super = parentCtor.prototype;
};

// Parent class dev
var Parent = function(){};
Parent.prototype.sayHi=function(){
  console.log("hi from Parent");
}
// end class
// Child class dev
var Child = function(){}
goog.inherits(Child,Parent);
Child.prototype.sayHi=function(){
  //_super only works on parent.prototype
  //this is where functions are usually defined
  //have to add this. to call _super as well
  this._super.sayHi();
  console.log("hi from Child");
}
// end Child

//code to test
var c = new Child();
c.sayHi();//hi from Parent and hi from Child

As I've commented; if you have trouble with the JavaScript syntax then typescript could be a good alternative.

Even if you find a way to write helper functions and make JS constructor functions look like Java classes you have to understand prototype.

Here is a helper function that I use for inheritance and overriding (calling super) using JavaScript (without Object.create)

I know this doesn't answer your question because as far as I know there is no good way to put everything in the function constructor and have it use prototype.

Note
Rectangle 27 0

javascript How to achieve pseudo classical inheritance right on the class declaration?


There's an exhaustive tutorial on how to do what you're after.

Note
Rectangle 27 0

javascript How to achieve pseudo classical inheritance right on the class declaration?


var myClass = $.cls({
    main: function() {
        $('body').append('My App is loaded <br/>');
    }
});

var mySecondClass = $.cls({
    main: function() {
        this._super();
        $('body').append('My Second App is loaded <br/>');
    }
}, myClass);

var app = new mySecondClass();

You can always try jOOP, though it does require jQuery.

Note