Just JavaScript - The Search for Type
Written by Ian Elliot   
Monday, 22 October 2018
Article Index
Just JavaScript - The Search for Type
Finding The Constructor
Instanceof

 

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

For example, every object is an instance of Object as well as whatever 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 having 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. See the previous chapter for a full discussion.

For example, if an object d has a prototype chain:

c → b → a → Object.prototype → 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 again 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 anywhere in the object’s 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 anywhere in the object's prototype chain. 

So if obj instanceof C is true you can't conclude that C was the object’s constructor. All you can conclude is that object has a specific prototype object P in its prototype chain and 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 an instance of B 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 b 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 B "inherits" from A 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.prototype → 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:

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

Final version in book

 

Summary

 

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

  • The prototype chain provides an analog of subtype.

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

 

This is an extract from the book Just JavaScript by Ian Elliot.

Buy Now: from your local Amazon

Just JavaScript 
An Idiomatic Approach

JustJavaScriptSmall

A Radical Look At JavaScript

 

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.

Contents

  1. JavaScript – Essentially Different
  2. In The Beginning Was The Object
  3. Real World Objects 
  4. The Function Object
          Extract - The Function Object
          Extract - Function Object Self Reference
  5. The Object Expression
  6. Function Scope, Lifetime & Closure
    Extract Scope, Lifetime & Closure
    Extract Execution Context ***NEW!
  7. Parameters, Returns and Destructuring
         Extract - Parameters, and Destructuring
  8. How Functions Become Methods
  9. Object Construction
         Extract: - Object Factories
  10. The Prototype
         Extract - ES2015 Class and Extends
  11. Inheritance and Type
  12. The Search For Type
  13. Property Checking

Buy Now: from your local Amazon

Also by Ian Elliot 
JavaScript Async: Events, Callbacks, Promises and Async Await
Just jQuery: The Core UI 
Just jQuery: Events, Async & AJAX  

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

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

espbook

 

Comments




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



Last Updated ( Monday, 22 October 2018 )