JavaScript Object Constructors & Prototypes

up:: JS Objects

Basic syntax

function Bird() { 
	this.name = "Albert"; 
	this.color = "blue"; 
	this.numLegs = 2; 
}
let parrot = new Bird();

Best practise

Objects are written in title case to distinguish from functions.

Terminology

The created object from a constructor is called an instance. For example, in the code above, parrot is the instance.

Prototypes

All objects in JS (with some exceptions) have a prototype. Because prototype is an object, it itself can have a prototype!

function Bird(name) {
  this.name = name;
}
 
typeof Bird.prototype;
 
let duck = new Bird("Donald");

This evaluates to Object.prototype.

It’s great because of prototype chaining, we can access all of the Object’s prototype functions from the Bird object. That’s where .hasOwnProperty() comes from! Not being able to access that implemented method is an example of Abstraction.

Here is the chain:

  • Bird is the supertype for duck.
    • duck is the subtype of Bird
  • Object is the supertype for Bird and duck, and all objects in JavaScript.

This is the basics of Inheritance.

Setting child prototypes

This can also be used for Don’t repeat yourself purposes: If Bird and Dog each have the same function of eat() in their properties, move it to an Animal supertype.

Then, you can create a subclass with all of the properties (the prototype) of the superclass:

Bird.prototype = Object.create(Animal.prototype);
 
// Created elements inherit the constructor from superclass
let duck = new Bird();
duck.constructor // => Animal
 
// That often isn't what we want. So make sure to set the constructor explicitly.
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;

Mixins

For unrelated shared functions, mixins are more appropriate than inheritance.

let flyMixin = function(obj) {
  obj.fly = function() {
    console.log("Flying, wooosh!");
  }
};
 
let bird = {
  name: "Donald",
  numLegs: 2
};
 
let plane = {
  model: "777",
  numPassengers: 524
};
 
flyMixin(bird);
flyMixin(plane);

flyMixin add the fly() function to the object passed in.

Closure

All of the code being able to access properties of an object can be dangerous. Think about passwords or bank account being able to be modified from anywhere in a codebase.

By defining a variable inside the function, it can’t be modified. This is the basic principle of Encapsulation.

function Bird() {
  let hatchedEgg = 10;
 
  this.getHatchedEggCount = function() { 
    return hatchedEgg;
  };
}
let ducky = new Bird();
ducky.getHatchedEggCount();

Modules

We can use immediately invoked function expressions (IIFE) to group multiple functions to add on objects. See below:

let motionModule = (function () {
  return {
    glideMixin: function(obj) {
      obj.glide = function() {
        console.log("Gliding on the water");
      };
    },
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log("Flying, wooosh!");
      };
    }
  }
})();
 
motionModule.glideMixin(duck);
duck.glide();