How does it work - Core Javascript (Part 2)

In first part, JavaScript Object Graph - Part-1, we covered basic JavaScript semantics. Here in this article we would dive deeper. Here we would cover classical, prototypal and object factory constructors.

The goal for this post is to help developer understand the strengths and weaknesses of each technique and understand what’s going under the hood.

Classical JavaScript Constructors

In JavaScript there are no classes. Function with prototype is nearest thing one can find in core JavaScript. It working differs somewhat comparing to class semantics used in most languages out there; but its very powerful and efficient

//define rectangle function
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
// add prototype getArea
Rectangle.prototype.getArea = function getArea() {
  return this.width * this.height;
};
// add prototype getPerimeter
Rectangle.prototype.getPerimeter = function getPerimeter() {
  return 2 * (this.width + this.height);
};
Rectangle.prototype.toString = function toString() {
  return this.constructor.name + " area =" + this.getArea() + " perimeter =" + this.getPerimeter();
};

Now let’s define a another class of objects called Squares that inherit from Rectangles. To do inheritance, the constructor’s prototype has to inherit from the parent constructor’s prototype. Here we’re overriding getPerimeter to make it slightly more efficient and to show how to override functions.

//square
function Square(side) {
  this.width = side;
  this.height = side;
}
// Make Square inherit from Rectangle
Square.prototype = Object.create(Rectangle.prototype, { constructor: { value: Square } });
// Override a method
Square.prototype.getPerimeter = function getPerimeter() {
  return this.width * 4;
};

Now its can be used as we use Rectangle functions. Create an instance and call function

var rectangle = new Rectangle(6, 4);
var square = new Square(5);
console.log(rectangle.toString());
console.log(square.toString());

Look at diagram below, dashed lines points to parent property.

classical - Core Javascript

Notice that there is little difference between the rectangle instance and Square.prototype. They are both simply objects that inherited from Rectangle.prototype. JavaScript is just a series of layered objects when you get down to it.

The only objects that are special are functions in that they take parameters and can hold executable code and point to scopes.

Pure Prototypal Objects

Let’s do the same example, but without using constructor functions. This time we’ll just use plain prototypical inheritance.

In prototypical pattern; we would just define an object containing both attributes and methods.

Let’s again define a Rectangle prototype that the base pattern for all our objects.

var Rectangle = {
  name: "Rectangle",
  getArea: function getArea() {
    return this.width * this.height;
  },
  getPerimeter: function getPerimeter() {
    return 2 * (this.width + this.height);
  },
  toString: function toString() {
    return this.name + " area =" + this.getArea() + " perimeter=" + this.getPerimeter();
  }
};

Now let’s create another object from our base object Rectangle called Square using Object.create and override some of the properties to amend its behavior

//square
var Square = Object.create(Rectangle);
Square.name = "Square";
Square.getArea = function getArea() {
  return this.width * this.width;
};
Square.getPerimeter = function getPerimeter() {
  return this.width * 4;
};

To create actual instances of these prototypes, we simply create new objects that inherit from the prototype objects and then set their local state manually.

var rect = Object.create(Rectangle);
rect.width = 6;
rect.height = 4;
var square = Object.create(Square);
square.width = 5;
console.log(rect.toString());
console.log(square.toString());

Here is the resultant graph of objects.

prototypal - Core Javascript

This isn’t quite as powerful as the constructor + prototype method, but is often much easier to understand since there is less indirection. Also if you come from a language that has pure prototypical inheritance, you’ll be happy to know it’s possible in JavaScript too.

Conclusion

There is so much more we can explore in addition to what described above like adaptor, factory and other design patterns; there is no inbuilt way to implement those; but developers can implement them as per their taste. If time permits I would write up a post describing how we can implement design patterns in Javascript too.


About The Author

I am Pankaj Baagwan, a System Design Architect. A Computer Scientist by heart, process enthusiast, and open source author/contributor/writer. Advocates Karma. Love working with cutting edge, fascinating, open source technologies.

  • To consult Pankaj Bagwan on System Design, Cyber Security and Application Development, SEO and SMO, please reach out at me[at]bagwanpankaj[dot]com

  • For promotion/advertisement of your services and products on this blog, please reach out at me[at]bagwanpankaj[dot]com

Stay tuned <3. Signing off for RAAM