Javascript: prototype-based programming

As a developer coming from an object-oriented programming background (e.g. C++, Java, etc.), you're probably wondering how to create classes in Javascript. But Javascript is a prototype-based language, a style of object-oriented programming (OOP) in which there are no classes. If there are no classes, how exactly is this a style of OOP?

Prototype-based vs classical object-based programming

The main difference between these two styles of programming lies in their approach to behavior reuse or, in classical OOP terminology, inheritance:

  1. In classical inheritance, you as a developer write a class, an abstract definition or blueprint from which object instances will be created. If you want to extend the behavior of your class, you write a subclass extending the parent's class behavior.

  2. In prototype-based programming, there are no abstract definitions of objects, no classes. You actually skip the definition of an abstract class and go straight to creating a concrete object: an object instance in classic OOP if you want. In fact, to make a new object you make a copy of an existing one!. The original object serves as the prototype for the copy, and the copy inherits the object's original behaviors. The new object is almost empty with basically a pointer to it's prototype. This is what is referred as delegation of behavior, the corner-stone of prototype based programming.

In order to better understand these concepts, let's first review objects in Javascript and how to create them.

Javascript Objects

As defined in the ECMAScript Language Specification, an object in Javascript is a collection of properties. Properties are containers that hold other objects, primitive values, or functions. A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, and String; an object is a member of the remaining built-in type Object; and a function is a callable object.

var Dog = {
    name: "Spike",
    breed: "Bulldog" 
};

The previous example is a Dog object created using the object literal notation which creates objects "from scratch". But wait, didn't I say that "to make a new object you make a copy of an existing one"? Yes, I did. When creating an object "from scratch", the new object is actually a copy of the root object called "Object". The root object is used as the default prototype. This object creation method is known as "ex-nihilo" or "from nothing".

The other alternative to creating objects is via a constructor (not to be confused with the classical OOP constructor). A constructor is a function used with the new operator to create objects.

function Dog(name, breed) {
   this.name = name;
   this.breed = breed;
}

var myDog = new Dog("Spike","Bulldog");

The use of the new keyword is critical. If you just call the Dog() function, you will be calling function Dog() as a subroutine and a name and breed variables will be created in the global context! Another important thing to mention, is that a function constructor in Javascript by default returns the newly created object, or "this". However, it is indeed possible to have a return statement and return something other that "this", but I would not recommend to do this unless you seriously know what you're doing.

Javascript's prototype inheritance by example

var Dog = {
    name: "Spike",
    breed: "Bulldog" 
};

// This statement returns true
console.log(Dog.constructor == Object);

// This statement also returns true
console.log(Dog.constructor.prototype == Object.prototype);

In the previous sample code, the Dog object created using an object literal was actually cloned behind the scenes from the root object "Object": the Dog object's implicit constructor function is "Object" (the standard built-in constructor) and the prototype from which it was created is Object.prototype.

function Dog(name, breed) {
   this.name = name;
   this.breed = breed;
}
var myDog = new Dog("Spike","Bulldog");

// This statement returns true
console.log(myDog.constructor == Dog);

// This statement returns true
console.log(myDog.constructor.prototype == Dog.prototype);

If we perform the same tests with the object created with a constructor, note how in this case myDog's constructor references the Dog object and the prototype from which it was created is Dog.prototype.

As you may have already noticed, objects in Javascript have a "constructor". The constructor property stores a reference to the object's constructor. The constructor object has a "prototype" property that stores a reference to its original prototype. In some Javascript implementations, there is also a "__proto__" property that holds a reference to the prototype of the object's constructor, but this is a non-standard feature which has already been deprecated. If this was confusing, this may explain it better:

  • myDog.constructor == Dog
  • myDog.constructor.prototype == Dog.prototype
  • myDog.__proto__ == myDog.constructor.prototype

That's it for this post. In the next one, we'll continue reviewing prototype inheritance and the prototype chain.

Cheers,
D

comments powered by Disqus