No. No. It will not happen. You are doing JavaScript inheritance all wrong. Your code gives me a migraine.
Creating a pseudo-classic inheritance pattern in JavaScript
If you need something similar to classes in JavaScript, then there are many libraries that provide this for you. For example, using augment , you can rebuild your code as follows:
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"); }; });
I do not know about you, but for me it is very similar to the classic inheritance in C ++ or Java. If this solves your problem, great! If not, continue reading.
Class prototype isomorphism
In many 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 see how prototype inheritance works :

The above image was taken from the following answer . I suggest you read it carefully. The chart shows us:
- Each constructor has a
prototype property that points to a prototype object of the constructor function. - Each prototype has a
constructor property that points to the constructor function of the prototype object. - We create an instance from the constructor function. However, the instance actually inherits from
prototype , not the constructor.
This is very useful information. Traditionally, we always created a constructor function, and then set its prototype properties. However, this information shows us that we can first create a prototype object, and then define the constructor property instead.
For example, traditionally we can write:
function ABC(key, value) { this.key = key; this.value = value; } ABC.prototype.what = function() { alert("what"); };
However, using our newfound knowledge, we can write the same thing as:
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; }
As you can see, encapsulation is easily achieved in JavaScript. All you have to do is think sideways. Inheritance, however, is another problem. You need to do a little more work to achieve inheritance.
Inheritance and super
See how augment reaches inheritance :
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; }
Note that the last three lines are the same as CLASS from the previous section:
function CLASS(prototype) { var constructor = prototype.constructor; constructor.prototype = prototype; return constructor; }
This tells us that when we have a prototype object, we only need to get its constructor property and return it.
The first three lines of the supplement are used for:
- Get a prototype base class.
- Create a prototype of the derived class using
Object.create . - Fill out the prototype of the derived class with the specified properties.
That's all there is to JavaScript inheritance. If you want to create your own classic inheritance pattern, you should think along the same lines.
True Prototypal Inheritance Coverage
Every JavaScript developer who deserves his salt will tell you that prototypal inheritance is better than classical inheritance.Nevertheless , beginners who come from a language with classic inheritance always try to implement classical inheritance on top of prototypal inheritance, and usually they fail.
They fail not because it is not possible to implement classical inheritance on top of prototype inheritance, but because to implement classical inheritance on top of prototype inheritance you need to first understand how true prototype inheritance works .
However, once you understand true prototype inheritance, you will never want to return to classical inheritance. I also tried before to implement classical inheritance from above prototype inheritance as a beginner. Now that I understand how true prototype inheritance works, I write the code as follows:
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; } }
The above extend function is very similar to augment , however, instead of returning a constructor function, it returns a prototype object. This is actually a very neat trick that allows you to inherit static properties. You can create a class using extend as follows:
var Abc = extend(Object, function () { this.constructor = function (key, value) { this.value = 333 + Number(value); this.key = key; }; this.what = function () { alert("what"); }; });
Inheritance is just as simple:
var Xyz = extend(Abc, function (base) { this.constructor = function (key, value) { base.constructor.call(this, key, value); }; this.that = function () { alert("that"); }; });
Remember, however, that extend does not return a constructor function. It returns a prototype object. This means that you cannot use the new keyword to instantiate a class. Instead, you need to use new as a method, as follows:
var x = Xyz.new("x", "123"); var y = Xyz.new("y", "456"); var it = Abc.new("it", "789");
This is actually good. The new keyword is considered malicious , and I highly recommend that you stop using it . For example, it is impossible to use apply with the new keyword . However, you can use apply with the new method as follows:
var it = Abc.new.apply(null, ["it", "789"]);
Since Abc and Xyz are not constructor functions, we cannot use instanceof to check if an object is an instance of Abc or Xyz . However, this is not a problem because JavaScript has a method called isPrototypeOf that checks if the object is a prototype of another object:
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));
In fact, isPrototypeOf more powerful than instanceof , because it allows us to check whether one class extends to another class:
alert(Abc.isPrototypeOf(Xyz)); // true
Apart from this minor change, everything else works the same as before:
x.what(); y.that(); it.what(); it.that(); // will throw; it is not Xyz and does not have that method
See a demo for yourself: http://jsfiddle.net/Jee96/
What else does true prototype inheritance offer? One of the biggest advantages of true prototype inheritance is that there is no difference between normal properties and static properties that allow you to write code like this:
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"); }; });
Note that we can instantiate a class from the class itself by calling this.new . If this.constructor is not yet defined, it returns a new uninitialized instance. Otherwise, it returns a new initialized instance.
In addition, since Xyz is a prototype object, we can directly access Xyz.empty (i.e. empty is a static property of Xyz ). It also means that static properties are automatically inherited and are no different from ordinary properties.
Finally, since the class is accessible from the class definition as this , you can create nested classes that inherit from the class in which they are nested using extend as follows:
var ClassA = extend(Object, function () { var ClassB = extend(this, function () {
See a demo for yourself: http://jsfiddle.net/Jee96/1/