JavaScript's object-oriented implementation – using prototypes

JavaScript is a class-less language. That's not to mean it is less fashionable or more blue-collar than other computer languages; class-less means it doesn't have a class structure in the same way that object-oriented languages do. Instead, it uses prototypes for inheritance.

Although this may be baffling to programmers with backgrounds in C++ and Java, prototype-based inheritance can be much more expressive than traditional inheritance. The following is a brief comparison between the differences between C++ and JavaScript:

C++

JavaScript

Strongly typed

Loosely typed

Static

Dynamic

Class-based

Prototype-based

Classes

Functions

Constructors

Functions

Methods

Functions

Inheritance

Before we go much further, let's make sure we fully understand the concept of inheritance in object-oriented programming. Class-based inheritance is demonstrated in the following pseudo-code:

class Polygon {
  int numSides;
  function init(n) {
    numSides = n;
  }
}
class Rectangle inherits Polygon {
  int width;
  int length;
  function init(w, l) {
    numSides = 4;
    width = w;
    length = l;
  }
  function getArea() {
    return w * l;
  }
}
class Square inherits Rectangle {
  function init(s) {
    numSides = 4;
    width = s;
    length = s;
  }
}

The Polygon class is the parent class the other classes inherit from. It defines just one member variable, the number of sides, which is set in the init() function. The Rectangle subclass inherits from the Polygon class and adds two more member variables, length and width, and a method, getArea(). It doesn't need to define the numSides variable because it was already defined by the class it inherits from, and it also overrides the init() function. The Square class carries on this chain of inheritance even further by inheriting from the Rectangle class for its getArea() method. By simply overriding the init() function again such that the length and width are the same, the getArea() function can remain unchanged and less code needs to be written.

In a traditional OOP language, this is what inheritance is all about. If we wanted to add a color property to all the objects, all we would have to do is add it to the Polygon object without having to modify any of the objects that inherit from it.

JavaScript's prototype chain

Inheritance in JavaScript comes down to prototypes. Each object has an internal property known as its prototype, which is a link to another object. That object has a prototype of its own. This pattern can repeat until an object is reached that has undefined as its prototype. This is known as the prototype chain, and it's how inheritance works in JavaScript. The following diagram explain the inheritance in JavaScirpt:

JavaScript's prototype chain

When running a search for an object's function definition, JavaScript "walks" the prototype chain until it finds the first definition of a function with the right name. Therefore, overriding it is as simple as providing a new definition on the prototype of the subclass.

Inheritance in JavaScript and the Object.create() method

Just as there are many ways to create objects in JavaScript, there are also many ways to replicate class-based, classical inheritance. But the one preferred way to do it is with the Object.create() method.

var Polygon = function(n) {
  this.numSides = n;
}

var Rectangle = function(w, l) {
  this.width = w;
  this.length = l;
}

// the Rectangle's prototype is redefined with Object.create
Rectangle.prototype = Object.create(Polygon.prototype);

// it's important to now restore the constructor attribute
// otherwise it stays linked to the Polygon
Rectangle.prototype.constructor = Rectangle;

// now we can continue to define the Rectangle class
Rectangle.prototype.numSides = 4;
Rectangle.prototype.getArea = function() {
  return this.width * this.length;
}

var Square = function(w) {
  this.width = w;
  this.length = w;
}
Square.prototype = Object.create(Rectangle.prototype);
Square.prototype.constructor = Square;

var s = new Square(5);
console.log( s.getArea() ); // 25

This syntax may seem unusual to many but, with a little practice, it will become familiar. The prototype keyword must be used to gain access to the internal property, [[Prototype]], which all objects have. The Object.create() method declares a new object with a specified object for its prototype to inherit from. In this way, classical inheritance can be achieved in JavaScript.

Note

The Object.create() method was introduced in ECMAScript 5.1 in 2011, and it was billed as the new and preferred way to create objects. This was just one of many attempts to integrate inheritance into JavaScript. Thankfully, this method works pretty well.

We saw this structure of inheritance when building the Maybe classes in Chapter 5, Category Theory. Here are the Maybe, None, and Just classes, which inherit from each other just like the preceding example.

var Maybe = function(){}; 

var None = function(){}; 
None.prototype = Object.create(Maybe.prototype);
None.prototype.constructor = None;
None.prototype.toString = function(){return 'None';};

var Just = function(x){this.x = x;};
Just.prototype = Object.create(Maybe.prototype);
Just.prototype.constructor = Just;
Just.prototype.toString = function(){return "Just "+this.x;};

This shows that class inheritance in JavaScript can be an enabler of functional programming.

A common mistake is to pass a constructor into Object.create() instead of a prototype object. This problem is compounded by the fact that an error will not be thrown until the subclass tries to use an inherited member function.

Foo.prototype = Object.create(Parent.prototype); // correct
Bar.prototype = Object.create(Parent); // incorrect
Bar.inheritedMethod(); // Error: function is undefined

The function won't be found if the inheritedMethod() method has been attached to the Foo.prototype class. If the inheritedMethod() method is attached directly to the instance with this.inheritedMethod = function(){...} in the Bar constructor, then this use of Parent as an argument of Object.create()could be correct.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.151.44