[JavaScript] Object Oriented Programming

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


Objects have properties and methods.

let dog = {
  name: "Spot",
  numLegs: 4,
  sayLegs: function() {return `This dog has ${this.numLegs} legs.`;}
};

dog.sayLegs();

Object Constructor Function

//constructor function
function Dog(name, color) {
    this.name = name;
    this.color = color;
    this.numLegs = 4;
}

let myDog = new Dog("Max", "Brown");

myDog instanceof Dog; // true
  • Constructors are defined with a capitalized name to distinguish them from other functions that are not constructors.
  • Constructors use the keyword this to set properties of the object they will create. Inside the constructor, this refers to the new object it will create.
  • Constructors define properties and behaviors instead of returning a value as other functions might.

Get Objects Own Properties

let ownProps = [];

for (let property in myDog) {
  if (myDog.hasOwnProperty(property)) ownProps.push(property);
}

console.log(ownProps); // returns [ "name", "color", "numLegs" ]

Prototype Properties to Reduce Duplicate Code

If all instances of an object have the same value for a property, define a prototype to share this property among all instances.

function Dog(name) {
  this.name = name; //own property
}

// To add a sinlgle protoype property
Dog.prototype.numLegs = 4; // prototype property

// To add a few at once
Dog.prototype = {
  constructor: Dog;
  numLegs: 4, 
  sayName: function() {
    console.log("My name is " + this.name);
  }
}

Note: There are two kinds of properties: own properties and prototype properties!

let myDog = new Dog("Max");
let ownProps = [];
let prototypeProps = [];

for (let property in myDog) {
  if (myDog.hasOwnProperty(property)) {    
    ownProps.push(property); 
  } else {
    prototypeProps.push(property);
  };
} 

console.log(ownProps); // returns [ "name" ]
console.log(prototypeProps); // returns ["numLegs"]

Note: The hasOwnProperty method is defined in Object.prototype, which can be accessed by Dog.prototype, which can then be accessed by myDog. This is an example of the prototype chain.


Constructor Property

Note that the constructor property is a reference to the constructor function that created the instance. The advantage of the constructor property is that it’s possible to check for this property to find out what kind of object it is.

console.log(myDog.constructor === Dog);  //prints true

It’s generally better to use the instanceof method to check the type of an object.


Inherit Behaviors from a Supertype

function Animal() { }

Animal.prototype = {
  constructor: Animal,
  eat: function() {
    console.log("nom nom nom");
  }
};

function Dog() { }

// Set the prototype of Dog to be an instance of Aninmal
Dog.prototype = Object.create(Animal.prototype);
// Set the constructor to Dog, else it would be function Animal(){...}
Dog.prototype.constructor = Dog;
// A method only the Dog needs
Dog.prototype.bark = function() {
  console.log("Woof!");
};

let myDog = new Dog();
myDog.eat();
myDog.bark();

// To override an inherited method, just use the same method name as the one to override
Dog.prototype.eat = function() {
  console.log("yami yami yami");
};
myDog.eat(); // returns yami yami yami

This is how JavaScript looks for the method:

  1. myDog => Is eat() defined here? No.
  2. Dog => Is eat() defined here? => Yes. Execute it and stop searching.
  3. Animal => eat() is also defined, but JavaScript stopped searching before reaching this level.
  4. Object => JavaScript stopped searching before reaching this level.

Mixin to Add Common Behavior Between Unrelated Objects

Inheritance does not work well for unrelated objects like Bird and Boat. They can both glide, but a Bird is not a type of Boat and vice versa.
For unrelated objects, it’s better to use mixins. A mixin allows other objects to use a collection of functions.

let bird = {
  name: "Ducky",
  numLegs: 2
};

let boat = {
  name: "Titanic",
  type: "CruiseShip"
};

let glideMixin = function(obj) {
  obj.glide = function() {
    console.log("Able to glide!");
  }
}

// Adds the method glide to both objects
glideMixin(bird);
glideMixin(boat);

bird.glide();
boat.glide();

Private Properties (Closure)

function Bird() {
  let weight = 15; // private variable

  this.getWeight = function() {
    return weight;
  };
}

let ducky = new Bird();
ducky.getWeight(); // returns 15

Immediately Invoked Function Expression (IIFE)

// function declaration and function call
function makeNest() {
  console.log("A cozy nest is ready");
}

makeNest();

//IIFE
(function () { 
  console.log("A cozy nest is ready"); 
})();

Note that the function has no name and is not stored in a variable. The two parentheses () at the end of the function expression cause it to be immediately executed or invoked.


Use an IIFE to Create a Module

let myModule = (function () {
    return {
        isCuteMixin: function (obj) {
            obj.isCute = function () {
                return true;
            };
        },
        singMixin: function (obj) {
            obj.sing = function () {
                console.log("Singing to an awesome tune");
            };
        }
    }
})();

myModule.singMixin(myDog);
myDog.sing(); // return Singing to an awesome tune

Leave a Reply

Your email address will not be published. Required fields are marked *