views:

460

answers:

3

I see a lot of code like this:

function Base() {}
function Sub() {}
Sub.prototype = new Base();

However, if you do:

s = new Sub();
print(s.constructor == Sub);

This is false. This seems confusing to me, since s's constructor is, indeed, Sub. Is it conventional/better to do this?

function Base() {}
function Sub() {}
Sub.prototype = new Base();
Sub.prototype.constructor = Sub;

or does it not really matter?

+3  A: 

If you want to test whether an object is exactly an instance of Sub use the instanceof operator:-

print(s instanceof Sub);

If you want to know whether an object is an instance of Sub or an instance of a sub-class of Sub use the isPrototypeOf method:-

print(Sub.prototype.isPrototypeOf(s));
AnthonyWJones
thanks for the advice, it makes sense.
Claudiu
Another good one Anthony ;)
Rob
+5  A: 

'constructor' doesn't do what it looks like it does. This, in addition to its non-standardness, is a good reason to avoid using it - stick with instanceof and prototype.

Technically: 'constructor' is not a property of the 's' instance, it is a property of the 'Sub' prototype object showing through. When you create the 'Sub' function in Mozilla, you get a newly-minted default Sub.prototype object which has a 'constructor' pointing back to the Sub function as a courtesy.

However you then replace that prototype with a new Base(). The original default prototype with the link back to Sub is lost; instead, Sub.prototype is an instance of Base without any overriding 'constructor' property. So:

new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base

...all the way down to the most basic object whose prototype you didn't change.

Is it conventional/better to do this?

When dealing with JavaScript objects/classes there is no one convention; every library's metaclass system behaves slightly differently. I haven't seen one that writes 'constructor' to each derived class manually, but it seems as good a solution as any if you really want to have the real constructor available; it will also make the code compatible with browsers/engines that don't give you 'constructor'.

I'd consider giving it a different name, though, to avoid confusion with the existing and differently-behaving 'constructor' property.

bobince
A: 

Yeah,

Sub.prototype.constructor = Sub;

let's you use instanceof but there's a better solution. Look here: ,TDD JS Inheritance on GitHub ,and find the Parasitic Combination Inheritance pattern. The code is TDD'd so you should be able to grok it very quickly and then simply change the names to get you started. This is basically what YAHOO.lang.extend uses (source: yahoo employee and author Nicholas Zakas's Professional JavaScript for Web Developer's, 2nd ED, page 181). Good book by the way (not affiliated in any way!)

Why? Because the classical pattern you're working with has staticy reference vars (if you create var arr = [1,2] in the base object, ALL instances will have read/write and will "share state" of 'arr'! If you use constructor stealing you can get around this. See my examples.

Rob