I get a strange bug when I implement inheritence in Javascript using prototypes. I am wondering if someone can explain this. In the following code,
I am trying to derive a child class from a parent class:
parent_class=function(byref)
{
if( !parent_class.prototype._vtbl )
{
parent_class.prototype.parent_func= function(o) { return alert("parent_func"); }
parent_class.prototype._vtbl = true;
}
}
child=function(byref)
{
parent_class.call(this,byref);
if( !child.prototype._vtbl )
{
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
}
function dotest()
{
var pub = new child;
alert( pub.child_func );
var pub2 = new child;
alert( pub2.child_func );
}
dotest();
When you run the test in a browser (Firefox or IE), you get two alerts. The first one says that pub.child_func is undefined, the second one says that the pub.child_func is a valid function and is parent_class.parent_func. Why do you see this behavior. Is this a bug?
Order of execution in javascript of such construct:
function SomeClass () { body(); }
var x = new SomeClass();
is this:
- new object which inherits from
SomeClass.prototype
is created (the prototype for the object is chosen here, before code of the constructor is executed)
body();
gets executed
- created object is assigned to x
What you can do in your example is use .__proto__
, although you really really should not:
child = function (byref) {
parent_class.call(this, byref);
if (!child.prototype._vtbl) {
child.prototype = new parent_class;
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
}
this.__proto__ = child.prototype;
}
What you really should do is this:
child = function (byref) {
parent_class.call(this, byref);
}
child.prototype = Object.create(parent_class.prototype);
child.prototype.child_func = parent_class.prototype.parent_func;
child.prototype._vtbl = true;
An easier way to do JavaScript inheritance might be the factory pattern:
function Animal(name) {
return {
run: function() {
alert(name + " is running!")
}
}
}
var animal = Animal("fox");
animal.run();
function Rabbit(name) {
var rabbit = Animal(name);
rabbit.bounce = function() {
this.run();
console.log(name + " bounces");
}
return rabbit;
}
var rabbit = Rabbit("rabbit");
rabbit.bounce();
Source: http://javascript.info/tutorial/factory-constructor-pattern
Short answer: No, it's not browser mistake, it's expected behavior.
Detailed answer:
When a constructor function is called with new
, reference to it's prototype
is copied into objects's __proto__
. Later on this property is used for prototypal lookups for this object.
Your code is really weird from point of view of javascript developer, when you modify prototype
of constructor during constructor call execution. However, it works. Because, after var parent = new parent_class();
the following is true parent.__proto__ === parent_class.prototype
. It is the SAME reference. Thus adding properties to parent_class.prototype
is automatically relfected in parent
object via prototypal lookup.
Unfortunately I can't post comments yet, so I have to reference from my answer, @RyszardFiński it is not a correct statement that prototype
is defined before contructor called and can't be changed afterwards. It is the same object and unless you change the reference changes will be reflected immediately for all instantiated objects
However in child
code in OP ruins references when child.prototype
is assigned to a new object.
child.prototype = new parent_class;
child.prototype
start pointing a to new instance of parent_class
(#1). Instance references look like below
pub.__proto__ === child.prototype
pub2.__proto__ === parentInstance1
child.prototype === parentInstance2
If you remove the line of code where child.prototype
is assigned everything will start working as you expect it
pub.__proto__ === child.prototype
pub2.__proto__ === child.prototype
child.prototype === child.prototype
child.prototype has properties _vtbl and child_func