I've:
function Obj1(param)
{
this.test1 = param || 1;
}
function Obj2(param, par)
{
this.test2 = param;
}
now when I do:
Obj2.prototype = new Obj1(44);
var obj = new Obj2(55);
alert(obj.constructor)
I have:
function Obj1(param) {
this.test1 = param || 1;
}
but the constructor function has been Obj2... why that? Obj1 has become the Obj2 prototype...
Can someone explain me, in detail, the prototype chain and the constructor property
Thanks
-
constructor
is a regular property of the prototype object (with theDontEnum
flag set so it doesn't show up infor..in
loops). If you replace the prototype object, theconstructor
property will be replaced as well - see this explanation for further details.You can work around the issue by manually setting
Obj2.prototype.constructor = Obj2
, but this way, theDontEnum
flag won't be set.Because of these issues, it isn't a good idea to rely on
constructor
for type checking: useinstanceof
orisPrototypeOf()
instead.
Andrey Fedorov raised the question why
new
doesn't assign theconstructor
property to the instance object instead. I guess the reason for this is along the following lines:All objects created from the same constructor function share the constructor property, and shared properties reside in the prototype.
The real problem is that JavaScript has no built-in support for inheritance hierarchies. There are several ways around the issue (yours is one of these), another one more 'in the spirit' of JavaScript would be the following:
function addOwnProperties(obj /*, ...*/) { for(var i = 1; i < arguments.length; ++i) { var current = arguments[i]; for(var prop in current) { if(current.hasOwnProperty(prop)) obj[prop] = current[prop]; } } } function Obj1(arg1) { this.prop1 = arg1 || 1; } Obj1.prototype.method1 = function() {}; function Obj2(arg1, arg2) { Obj1.call(this, arg1); this.test2 = arg2 || 2; } addOwnProperties(Obj2.prototype, Obj1.prototype); Obj2.prototype.method2 = function() {};
This makes multiple-inheritance trivial as well.
-
Check out Tom Trenka's OOP woth ECMAscript, the "Inheritance" page. Everything from the prototype is inherited, including the
constructor
property. Thus, we have to unbreak it ourselves:Obj2.prototype = new Obj1(42); Obj2.prototype.constructor = Obj2;
-
Well, the constructor property is a property like any other, on the prototype (property) of Obj1. If you understand how prototypes work, this might help:
>>> obj.hasOwnProperty("constructor") false // obj's [[Prototype]] is Obj2.prototype >>> Obj2.prototype.hasOwnProperty("constructor") false // Obj2.prototype's [[Prototype]] is Obj1.prototype >>> Obj1.prototype.hasOwnProperty("constructor") true // Oh? >>> Obj1.prototype.constructor Obj1()
Aha! So obj has no constructor, JS goes to get it up the [[Prototype]] chain, all the way from Obj1.prototype.constructor
I'm not sure why the constructor property isn't just set on an object when you use `new'. There might be a reason, or it might just be an oversight. Either way, I tend to avoid it.
Christoph : `constructor` is a property which is shared between all instance objects created from the same constructor, therefore, it's the right thing to put it in the prototype; it's just that JS has no built-in support for (deep) inheritance hierarchies - I'll add an explanation to my answer... -
Short version: ‘constructor’ doesn't do what you think, and isn't cross-browser compatible. Never use it.
Long version: http://stackoverflow.com/questions/402538/convention-for-prototype-inheritance-in-javascript/402919#402919
Generally: you're getting confused due to (a) the impedence mismatch between class-based and prototype-based OO, and (b) the strangeness of JavaScript's particular rather poor interpretation of prototype-based OO.
You'll probably be happier if you find one classes-in-prototypes implementation you like and stick with that. Many libraries have one. Here's an arbitrary one I use:
Function.prototype.subclass= function() { var c= new Function( 'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+ 'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); ' ); if (this!==Object) c.prototype= new this(Function.prototype.subclass.FLAG); return c; } Function.prototype.subclass.FLAG= new Object();
And here's an example of how one might use it:
// make a new class var Employee= Object.subclass(); // add members to it Employee.prototype._LEGS= 2; Employee.prototype.getLegs= function() { return this._LEGS; }; // optional initialiser, takes arguments from constructor Employee.prototype._init= function(name) { this.name= name; }; // make a subclass Manager= Employee.subclass(); // extend subclass method Manager.prototype._init= function(name, importance) { // call base class's method Employee.prototype._init.call(this, name); this.importance= importance; } // all managers are well-known to have three legs Manager.prototype._LEGS= 3; // create one var jake= new Manager('Jake the Peg', 100);
0 comments:
Post a Comment