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

JavaScript is a subtle and sophisticated language that deserves to be treated in its own right and not as a poor copy of other object-oriented languages. In the first of two explorations of how to live without type in JavaScript, we look at the constructor as a object's type and how instanceof provides subtypes. Next time we'll move on to realtime type checking and the prototype constructor.

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

Type In JavaScript

After a careful look at how other languages make use of type (see Just JavaScript - Type And Non-Type) we can get back to JavaScript. 

As long as you accept the fact that strong typing and hierarchical typing is only about determining what properties are safe to use then we can proceed.

It is true that type checking will detect errors, but the ones that it will detect are fairly easy to find by examining the source code without type checking.

Type checking answers the question

  • can I use property p on the object referenced by o?

where, for the sake of simplicity, property will also include methods which are just properties that happen to be Function objects. (Refer back to The Function Object if you are not comfortable with this)

If the object instance that o references is known at compile time then you can just look at the definition of the object and see if it has a property p

If the object instance that o references is not known at compile time then you have to wait and see and risk a runtime error. This is true even if the language you are using is strongly typed.

In JavaScript there is no class based type and objects are completely dynamic. Similarly variables are not typed and can reference any object. 

It is arguable that trying to identify the concept of type in JavaScript is entirely the wrong thing to do. It is simply an attempt to turn JavaScript into Java - or any strongly typed class based language you care to think of. 

However this hasn't stopped people trying to find suitable analogs of type and even class in JavaScript.

In this chapter we take a look at how close we can get to the idea of class based type in JavaScript.

As well as the the idea the two main ways that have been used to introduce class based type into JavaScript - the constructor property and the instanceOf operator are explain in detail. 

Beginners often think that constructor and instanceOf are the solution to the type problem - but they aren't they are just a different type of problem. 

In the next chapter we tackle the problem that type solves head on. You have to judge which works best for you - but first what sorts of things could stand in for class based type in JavaScript.

What Is Type?

To work out how to replace "type" in JavaScript we first have to answer the question - how do objects get properties?

In short, if an object has a property p how many ways are there it could have acquired it?

There are four general ways:

  1. static literal definition of properties
    var obj={a:1,b:2};

  2.  dynamic ad hoc properties
    obj.c=3

  3. Constructor or object factory
    var obj=new Obj();

  4.  via a prototype
    Obj.prototype=new Obj2();
    var obj=new Obj();

If you define a literal object then there is usually only one of them. If you want to create more than one then it is obvious that you should use a constructor or an object factory.

So finding out what properties a literal object has is a one-off task.

That is, it is a unique singleton object in your program and it should have a clearly defined set of properties. 

Dynamic properties, that is adding or removing a property at runtime, is much more problematic and in fact it is so messy that it is best treated as a variation on the other ways of dealing with the type problem. 

So this is how an object can acquire a property, but in JavaScript an object can also have a property removed. The delete operator can delete any property. 

Note: delete does not delete variables only properties. 

If you are trying to characterize the properties an object can be expected to have then you really have to ban dynamic ad hoc properties and the delete operator. In practice, we don't really have to ban dynamic ad-hoc properties because these merely add to the properties you can expect an object to have - the real problem is the delete operator. Fortunately this is rarely used. 

If we ignore the delete operator then there are two approaches to "type" in JavaScript depending on whether you want to focus on the constructor or the prototype. 

Put simply:

  • if you know an object's constructor you know the initial set of properties it has. These include the properties provided by the constructor and by the prototype chain. 

  • if you know that p is in the object's prototype chain then you know that the object at least supports the properties supplied by p

  • The constructor is like the object's type and its prototype chain defines its subtypes. 

Before we move on to focus on the constructor and prototype we need to take a moment to look at how prototype inheritance compares and contrasts with class based inheritance. 

Prototypical Inheritance

JavaScript is usually described as using prototypical inheritance.

What this means is that every object has a prototype chain of other objects which are used to supply properties not defined on the original object.

Every object has either null or null and Object in their prototype chain. It is quite easy to construct a prototype hierarchy that looks very much like a class based type hierarchy.

For example you could have an animal object, a dog object and a cat object and the following prototype hierarchy:

 

                                   null
                                     V
                                 Object
                                      |
                                 animal
                                     /  \
                                dog  cat

 

What this means is that both dog and cat have animal and Object as their prototype chain.

Notice that this is an object hierarchy not a class hierarchy. What this means is that each entity is an object. The animal object that is in dog and cat's prototype chain is the same object. 

This means that the animal object provides all of its properties to both dog and cat. This sounds very restrictive and suggests that dog and cat are some how sharing variables - they aren't. In fact the way this works is very similar to a class hierarchy.

Suppose the animal object has a size property giving the size of the animal then this simply sets the initial value of size for both dog and cat. As soon as dog or cat assigns their own value to size they get their own property.

That is dog and cat share the initial values of all properties as provided by animal. Notice that unless dog and cat override any functions they inherit animal provides the code and this is efficient. 

There are a number of differences between this and a class hierarchy. 

  • Although names have been given to the objects in the diagram - object's don't have names only variables that reference them. If the animal object is also referenced by another variable called creature then presumably it could also be called the creature object. 

  • If you create another animal object, i.e. an object with all the same methods and properties, then the new object would not be part of the hierarchy as drawn as it is a different object from the one labeled as animal. 

  • However any new animal object would have the same prototype chain leading back to Object and null. 

  • In a class hierarchy you can create an instance of a class and expect the system to supply all of the inherited methods. For example you could create a dog object from the Dog class without having to explicitly create an animal object first. In an object hierarchy all of the object have to explicitly be created. For example creating a dog object involves specifying an existing animal object as its prototype. 

Perhaps the most telling difference is the lack of an invariable name associated with an object. In a class based language you can define an Animal class and use this to stamp out lots of different instances and you would call these instances of Animal. You think of them as all being the same type of "thing". In a non-class language objects don't have this sort of "type" identity and they don't form natural groups.

In this sense in JavaScript every object is a singleton. 

 

Banner



Last Updated ( Sunday, 10 May 2015 )