It’s just a distillation from this & Object Prototype of YDKJS (You Don’t Know JavaScript) book series. I want to understand how classical object oriented style has been imposed on JavaScript for decades and how the true mechanism of [[Prototype]] chain works in accordance to alternative design pattern Kyle provides in his book (behaviour delegation or OLOO). Some eccentric German philosophers said, “You don’t really understand something until you are able to explain it to yourself in a simple manner!”

Let’s debunk all misconceptions about OOP in JavaScript in a simple manner!

1. No Such Thing Like Class!

  function Human(name) {
    this.name = name
    console.log("You are created by God!");
  }

  var me = new Human("Muhammad D. Ramadhan");
  me.name // Muhammad D. Ramadhan
  me.constructor === Human // true

  // You can't access [[Prototype]] like this, but
  // the statement below is true!
  me.[[Prototype]] === Human.prototype // true

Human is an ordinary function that happens to be paved over by new keyword, so it returns newly created object out of thin air in addition to executing all statements in its function’s body (this.name assignment and console.log). We’ll be back to this later.

Now, we have to understand what exactly [[Prototype]] property is.

You might have heard that every object in JavaScript is linked to other object via [[Prototype]]. That property is not accessible. However, in modern browser (most latest version of Chrome), you can access that property via __proto__.

  var foo = { name: "Your name" };
  foo.__proto__; // Object.prototype

You might have wondered how come we can access toString property?

  foo.toString() // [object Object]

We didn’t even declare toString property, right?

  var foo = {
    name: "Your Name",
    toString: function() {
      // Implementation...
    }
  };

In reality, foo object has link to Object.prototype object via [[Prototype]] property, so it looks up and follows the [[Prototype]] chain to find toString.

Let’s see how it’s done:

  // We actually access it via [[Prototype]] / __proto__.
  foo.__proto__.toString === Object.prototype.toString // true
  foo.toString === foo.__proto__.toString // true

Nah, how about that me object “constructed by” Human function above?

  me.constructor; // Human

See? It’s logical to assume that the me object is constructed by Human, right? That constructor property refers to Human function!

Well, don’t be fooled by that! It doesn’t mean me object is constructed by Human. As the subtitle said, “there’s no such thing like class!”

Everytime you declare a function, no matter what it is, you will get access to its own prototype property and the default value of that property is this object:

  Human.prototype;
  // { constructor: f }

Interestingly, that constructor property point back to the function itself:

  Human.prototype.constructor === Human // true

Bear it in mind, new Human("Muhammad D. Ramadhan"); will create new object and make its [[Prototype]] property link to Human.prototype, so that new object can access default Human.prototype’s properties (constructor in our case) or any properties you add to it later on. Here’s the example:

  function Human(name) {
    this.name = name;
    console.log("You are created by God!");
  }

  // Add new property, so new object created by construction call
  // (`new` keyword in front of ordinary function call) have access
  // to introduceOnceself indirectly via [[Prototype]].
  // No instantiation. No inheritance. It's just linking!
  Human.prototype.introduceOneself = function () {
    console.log(`My name is ${this.name} and I like ちえさ せれな`);
  };

  var me = new Human('Muhammad D. Ramadhan');
  me.introduceOneself();

  // My name is Muhammad D. Ramadhan and I like ちえさ せれな

Actually, we access introduceOneself property this way:

  me.__proto__.introduceOneself();
  me.__proto__ === Human.prototype // true
  me.__proto__.introduceOneself === Human.prototype.introduceOneself; // true
  me.introduceOneself === me.__proto__.introduceOneself; // true

The same thing goes to that bogus constructor property!

  me.__proto__.constructor === Human.prototype.constructor // true
  me.constructor === me.__proto__.constructor // true

Truth be told, we can override constructor or prototype! I don’t think I can rely on parent-children relationship if I can freely change those properties!

  Human.prototype = { constructor: "Ha ha ha, you are bogus!" };
  me = new Human("Muhammad D. Ramadhan");
  me.constructor // Ha ha ha, you are bogus!

2. It Is Really Complicated

Here’s how I implement classical object oriented style in JavaScript.

Bogus Object Oriented Programming

Follow the [[Prototype]] chain to look up properties not directly accessible on current object.

Alright then, that’s it for today. Next time, we are going to get rid of this complex mechanism using behaviour delegation (OLOO).