Introduction
JavaScript does not support classes, it works with prototypes that allow for fully dynamic object creation but if one wants to have a more class-like behavior
a few tricks and work-arounds are needed.
The code was initially developed for use on the server side in Microsoft IIS (Jscript) and will also be adapted
for client-side use (Browsers) and use in node.js, in future releases.
Basics: classic JavaScript inheritance
The easy way of inheriting from base "classes", as shown in most JavaScript programming guides:
1: function MyBaseClass()
2: { MyBaseClass.iUsageCount++;
3: return this;
4: }
6: MyBaseClass.iUsageCount=0;
8: function MyDerivedClass()
9: {
10: }
12: MyDerivedClass.prototype=new MyBaseClass();
13:
15: var jDerivedInstance=new MyDerivedClass();
16: jDerivedInstance instanceof MyDerivedClass;
17: jDerivedInstance instanceof MyBaseClass;
18: jDerivedInstance instanceof Object;
Now let's have a look at the effects of this kind of inheritance:
- Pro: Easy to implement, easy to remember, and also easy to forget writing line 13.
- Pro: instanceof works as expected.
- Con: In line 12, the base class´ constructor is called and the usage count is set to 1, although we didn´t really want to create a "real" instance.
- Con: When not using line 13, instance.constructor would point to
MyBaseClass
, which is not correct. When using line 13, instance.constructor tells us the correct "class"
name, but instance.constructor.prototype does not tell us the base class any more. - Con: On instantiation of the derived class in line 15, the base constructor is not automatically called -- we would have to call it explicitly.
A first improvement
Now we try fixing the first few things on the classic inheritance code:
[...]
8: function MyDerivedClass()
9: { MyDerivedClass.__base__.call(this);
10: }
12: MyDerivedClass.prototype=Object.create(MyBaseClass);
13: MyDerivedClass.prototype.constructor=MyDerivedClass;
14: MyDerivedClass.prototype.__proto__=MyBaseClass.prototype;
15: MyDerivedClass.__base__=MyBaseClass;
17: var jDerivedInstance=new MyDerivedClass();
The changes in behaviour are now:
- Pro: In line 12,
Object.Create
gives the benefit of creating the needed base class instance without calling its constructor. - Con: But in IIS and IE<9.0,
Object.Create
is not available, so we will show an emulation function in the next edition of this article. - Pro: In line 14, we set the de-facto-standard property "
__proto__
", so we get a path to walk the inheritance chain, when we need it. We also set
a non-standard "__base__
" property directly on the constructor, so it will be easy to call the base constructor (line 9).
A surrogate constructor helps
Don´t forget that under IIS and IE<9.0, we don't have "Object.create()
". But we can use a so-called surrogate constructor to clone
the class by its prototype without its original constructor.
[...]
8: function Surrogate()
9: {
10: }
12: Surrogate.prototype=MyBaseClass.prototype;
13: MyDerivedClass.prototype=new Surrogate();
14: MyDerivedClass.prototype.constructor=MyDerivedClass;
15: MyDerivedClass.prototype.__proto__=MyBaseClass.prototype;
16: MyDerivedClass.__base__=MyBaseClass;
18: var jDerivedInstance=new MyDerivedClass();
We construct the Surrogate
class instead of the base class for use as the derived class' prototype, so the base constructor is not called, as with Object.create
, which we don´t have.
Next part: constructor chaining
In the next part of this article, we will look at how we can build a constructor chaining mechanism into our inheritance mechanism,
so base constructors will be called automatically/implicitly, as known from languages such as C++ or C#.
Your comments are welcome!
History
This is the original edition of the article.