Just JavaScript - Life Without Type - Constructor And InstanceOf
Written by Ian Elliot   
Thursday, 05 March 2015
Article Index
Just JavaScript - Life Without Type - Constructor And InstanceOf
Finding the Constructor
Subtype

 

The Mystery Of Instanceof - Subtype

Knowing what type an object is isn't the end of the story.

In a class based language the type hierarchy means that it is possible to consider an object as being of a number of different types and sub-types.

For example, every object is an instance of Object as well as what ever class it actually is.

If class B inherits from class A then an instance of class B can be considered to be a class A instance as well as it has all of the properties and methods of an instance of class A.

This is the Liskov substitution principle and it applies, with some exceptions due to dynamic properties, in JavaScript. 

For example if an object d has a prototype chain:

c->b->a->Object->null

then it is not only an instance of D but it can also be treated as an instance of C, B or A. 

With this explained we can now understand the intention of the instanceof operator. 

The instanceof operator looks as if it is a way of testing to see if an object was constructed by a particular constructor but this isn't what it does at all. 

It is often explained that we can test to see if obj has constructor C using:

obj instanceof C;

which will return true if obj was constructed by C. 

This looks as if it is just an alternative to testing an object's constructor property but this is not what it is doing. 

The instanceof operator doesn't check the constructor but the prototype that the constructor specifies.

That is 

obj instanceof C:

compares the object's prototype to the prototype specified in the constructor. If they are the same then it might seem reasonable to conclude that obj was constructed by C.

But things are a little more complicated than this simple introduction suggests. 

Not only does instanceof test to see if the prototype the constructor specifies is the immediate prototype of the object it also checks to see if the prototype is any where in the objects complete prototype chain. 

So to be 100% clear:

  • obj instanceof C:
    looks for C.prototype in the object's entire prototype chain and returns true if it finds it. 

Instanceof doesn't test that the object was created by the constructor you specify. It tests if the object has the prototype specified by the constructor is in the object's prototype chain. 

So if obj instanceof C is true you can't conclude that C was the objects constructor. All you can conclude is that object has a specific prototype object P in its prototype chain in hence it has all of the properties of P. 

You could say that the statement

obj instanceof C

being true lets you conclude that obj is of type P where P is the prototype object specified by C. 

For example consider the following 

var p={x:10};

var A=function(){
 this.z=20;
};
A.prototype=p;

var B=function(){
 this.y=30;  
};
B.prototype=p; 

 

We have defined two different constructors A and B with the same prototype p.

That is the inheritance branches

     p
    /\
   a  b

 

Notice that A and B construct objects with different sets of properties - an instance of A has x and z and of D has x and y. 

Now if you create an object using B 

var b=new B();

and test using instanceof

console.log(b instanceof A);

you will discover that b is an instance of A (i.e. the result is true) even though it was created by B.

You can also see that there is no reasonable sense in which b is an instance of A - it only shares the same prototype with objects created by A.

In this sense it would be more reasonable to say that obj was a p.

So why did anyone add instanceof to JavaScript?

If you restrict yourself to a strictly non-branching inheritance structure then instanceof does sort of work.

If you change the previous example to one in which D "inherits" from C then it makes a little more sense:

var p={x:10};

var A=function(){ 
 this.z=20; 
}; 
A.prototype=p;

var B=function(){ 
 this.z=30;  
};
B.prototype=new A(); 

You can see that now we have an inheritance with no branches given by

b->a->p->object->null

i.e. any object created by B has all of the properties of one created by A and both have all of the properties of p.

Now if you create an instance of  B then  

var b=new B();

then 

console.log(b instanceof A);

is true because b has p in its prototype chain and because the inheritance is hierarchical it also has all of the properties of A. 

Notice also that in this case a A would not be considered to be an instance of a B because B's prototype is A and A is not in A's prototype chain. 

As long as you stick to a strict hierarchical non-branching"inheritance" using prototypes then the instanceof operator gives you the results you might expect. 

If the inheritance branches, as most do then you get a seemingly wrong answer from instanceof if you regard it as telling you about constructors. 

Where Are We

JavaScript provides two "helper" functions for programmers wanting to reinvent type but they both are very deeply flawed.

Knowing what an object's constructor is does specify what properties it has and so it is a reasonable interpretation of type. The problem is that the constructor property, which is supplied by the prototype object, is only set automatically for the default prototype object. If you supply a prototype object of your own to build up a prototype chain then you have remember to set its constructor property to reference the constructor. 

This can be made to work but it isn't ideal.

Knowing that a particular object p say is in and object's prototype chain lets you treat the object as if it was an instance of p i.e. its subtype is P. 

The instanceof operator doesn't check that an object is an instance of a particular constructor i.e. was created by the constructor as its name suggests. It simply checks to see if the prototype specified by the constructor is in the object's prototype chain. Hence it checks if the object is a subtype P the same as the prototype specified by the constructor.

The problem with the instanceof operator is that it seems to be checking for one thing and it actually checks, imperfectly for another. However the basic idea that a prototype being in an object's prototype chain determines a sort of analog of subtype is a good one. This idea shouldn't be thrown out along with the broken attempt at an instanceof operator.

It is clear that with the current model of prototype inheritance the best analog of type is the constructor and the best analog of sub-type is the prototype chain.

However at the start of the chapter it was suggested that trying to find an analog of class based type might not be a good idea at all and if it is then perhaps constructor/prototype definitions are not the way to go.

In the next chapter we meet duck testing and prototype construction as alternatives to class based type.

 

Summary

  • The constructor is the best analog of type in JavaScript.

  • The prototype chain provides an analog of sub-type.

  • The constructor property only works for the default prototype object.

  • If you supply a custom prototype then you have to set the constructor property.
  • The instanceof operator doesn't test for an instance of the specified constructor. It checks the prototype chain for the occurrence of the prototype specified by the constructor.
  • There are probably better ways of dealing with the lack of type in JavaScript. 

Just JavaScript 

 There is a newer version of the draft of the book here.

A Radical Look At JavaScript

Contents

  1. JavaScript Isn't Java, or C, or C# ... (Book Only)
  2. In The Beginning Was The Object
  3. The Function Object
  4. How Functions Become Methods
  5. The Object Expression
  6. Object Construction
  7. The Prototype
  8. Type And Non-Type
  9. Constructor And InstanceOf
  10. Duck Testing And Prototype Construction

-Preface-

Most books on JavaScript either compare it to the better known class based languages such as Java or C++ and even go on to show you how to make it look like the one of these.

Just JavaScript is an experiment in telling JavaScript's story "just as it is" without trying to apologise for its lack of class or some other feature. The broad features of the story are very clear but some of the small details may need working out along the way - hence the use of the term "experiment". Read on, but don't assume that you are just reading an account of Java, C++ or C# translated to JavaScript - you need to think about things in a new way. 

Just JavaScript is a radical look at the language without apologies. 

 

JustJavaScripticon

Related Articles

Late Binding - Myths and Reality

Just JavaScript - The Object Expression       

Covariance And Contravariance - A Simple Guide       

The Working Programmer's Guide To Language Paradigms       

Data Typing Is A Relic       

Strong Typing       

Weakly Typed Languages    

Type Systems Demystified         

Casting – the escape from strong typing       

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 

Banner


JavaScript Canvas - Fetch API

Working with lower-level data is very much part of graphics. This extract from Ian Elliot's book on JavaScript Graphics looks at how to use typed arrays to access graphic data.



JavaScript Jems - The Inheritance Tax

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, it doesn't do inheritance  [ ... ]


Other Articles

 

espbook

 

Comments




or email your comment to: comments@i-programmer.info

<ASIN:0596805527>

<ASIN:193398869X>

<ASIN:0137054890>

<ASIN:1449381871>

<ASIN:1430230541>



Last Updated ( Sunday, 10 May 2015 )