Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convention for prototype inheritance in JavaScript

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?

like image 638
Claudiu Avatar asked Dec 31 '08 08:12

Claudiu


People also ask

What is prototype inheritance in JavaScript?

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.

What is prototype and __ proto __ in JavaScript?

Prototypes is a simple way to share behavior and data between multiple objects access using .prototype. proto is also a way to share behavior and data between multiple objects access using __proto__ All the object constructors (function) have prototype properties. All the objects have proto property.

What is __ proto __ in JavaScript?

__proto__ is a way to inherit properties from an object in JavaScript. __proto__ a property of Object. prototype is an accessor property that exposes the [[Prototype]] of the object through which it is accessed. POSTly is a web-based API tool that allows for fast testing of your APIs (REST, GraphQL).

What is the difference between prototype and inheritance in JavaScript?

The most important difference between class- and prototype-based inheritance is that a class defines a type which can be instantiated at runtime, whereas a prototype is itself an object instance.


3 Answers

'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.

like image 143
bobince Avatar answered Nov 08 '22 07:11

bobince


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));
like image 39
AnthonyWJones Avatar answered Nov 08 '22 07:11

AnthonyWJones


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.

like image 33
Rob Avatar answered Nov 08 '22 06:11

Rob