Just JavaScript - Life Without Type - Constructor And InstanceOf |
Written by Ian Elliot | |||||||
Thursday, 05 March 2015 | |||||||
Page 3 of 3
The Mystery Of Instanceof - SubtypeKnowing 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:
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:
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
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:
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
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
We have defined two different constructors A and B with the same prototype p. That is the inheritance branches
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
and test using instanceof
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:
You can see that now we have an inheritance with no branches given by
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
then
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 WeJavaScript 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
Just JavaScriptThere is a newer version of the draft of the book here. A Radical Look At JavaScriptContents
-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.
Related ArticlesLate Binding - Myths and Reality Just JavaScript - The Object Expression Covariance And Contravariance - A Simple Guide The Working Programmer's Guide To Language Paradigms 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, Facebook, Google+ or Linkedin, or sign up for our weekly newsletter.
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 ) |