Featured post

Closures, Lexical Scoping And Scope chain In JavaScript

Closures...You have heard a lot, or might have tried to study from different sources, but failed to get the point. Well to under...

Wednesday 17 February 2016

Object Oriented JavaScript - Objects, Classes, Constructors, Prototype and Inheritance

First lets understand what is Object Oriented programming and then we will relate it to JavaScript.

Mozilla Foundation has given a generalized definition of OOP.
Object Oriented Programming is a programming paradigm that uses abstraction to create models based on the real world.
Object Oriented Programming uses self contained pieces of code to develop applications. We call those pieces Objects. Objects are building blocks of our application. In OOP each object can receive messages, process data and send messages to other objects. Objects allows to create modularize applications. In some strongly typed languages like Java, C++, Objects refers to the instances of classes but unlike these languages, in JavaScript functions accomplishes the behavior of any class and then uses it.

Some basic terminologies of OOP with which you should be aware of:

Namespace:
A container, to bundle all application logic under one unique name.

Class:
Defines object's behavior. React as template for object's properties and methods.

Object:
Instance of class.

Property:
Object's characteristic

Method:
Object's capability or subroutine.

Constructor:
Method called during object creation in order to initialize the object.

Inheritance:
Class inheriting properties of another class.

Encapsulation:
Process of bundling data and methods that use the data.

Polymorphism:
Multiple forms of same methods and properties.

JavaScript does not implement all the the above terms typically as other strictly typed languages does, but JavaScript has its own way of supporting OOP. For example some browsers do not support class implementation (as we can not define class according to ECMA Script 5 standards), but JavaScript defines a function which typically behaves as class.

JavaScript supports Prototype based programming that doesn't uses class, but rather it first accomplishes the behavior of any class and then reuses it by decorating existing prototype objects.

Classes and Prototype:


In JavaScript, classes are collection of objects which has same prototype object. Every function in JavaScript has inbuilt prototype property. All the objects inheriting from that function actually inherits from that prototype property. Function works as an Class for the objects which actually shares methods defined in prototype property.

Before creating any class, first lets understand how can we inherit an object into another or lets take a deep dive into JavaScript Objects.

JavaScript Objects:


There are multiple ways to create an object in JavaScript defined in different versions of ECMAScript. First, basic way to define an object is through Object Literals.

var o = {};      // object o
var obj = {
      x: "I am String",      // String
      y: 2      // Number
}      // object obj

Objects defined/created using above method inherits properties/methods from the Parent of all the Objects or say Base object of all the objects called "Object". (I know there are lot of objects in this sentence :/ )
In simple terms we can say, JavaScript has provided us with an predefined object which has some inbuilt methods and properties and which acts as an parent of all the objects. That predefined object has name Object. Some basic methods defined in this object are hasOwnProperty, length, toString, valueOf and etc.. We will explore some methods shortly.

Till now we know that each JavaScript object or function has inbuilt property "prototype" and value of prototype is an object from which it inherits properties.

That means, prototype property of object o (from above example) is an object from which it inherits. We have already seen that o inherits from Object. So,

Object.getPrototypeOf(o)      // This will obviously display Object object (Predefined object of JavaScript)

Now what if I override prototype property or set it to null? Well, this is bad idea, I mean very bad idea. You can always override this property but if you do so, you will loose all the inbuilt/basic methods that you are getting from Object object. And who wants that..No one.

Object.getPrototypeOf(o)      // Will display Object object
o.__proto__ = null;
Object.getPrototypeOf(o)      // Null
o.toString();      // Will display TypeError: function not defined.

Lets check out second way to create an object in JavaScript using Object.create() method. This method was introduced in ECMAScript 5.

var obj = Object.create();

This will create an object similar to the object o. Here obj will also inherit from the Object object. So why in the name of god we need to different ways.
There is an difference between these two. Using Object.create(), we can explicitly define from which particular object we want to inherit by passing that object as first parameter.

var parent = {
       a: "this is parent"
}
var child = Object.create(parent);

Now child object is inheriting from the parent object. That is prototype of child is set to parent. So what about all the predefined methods of Object object. Well prototype of parent object is Object object. With this prototype chain child object will be able to access Object object's predefined methods and properties.
What if we want to define as well as declare the properties of the new object at the same time using Object.create(). We can achieve that by passing the second optional parameter.

var child = Object.create({a: "parent property"}, {
      foo: { writable: true, configurable: true, value: "Everything is weird." }
});

child object have property foo whose value is "Everything is weird". (We will discuss writable and configurable property later.). Also child object inherits from the object passed in first parameter.

Object.create() was introduced in ECMAScript 5. So before ES5, there might be some another way to create an object with desired prototype. Lets define an inherit method which inherits from an object passed in as parameter.

function inherit(p) {
      if (p == null) {
            throw TypeError();
      }
      if (Object.create)
            return Object.create(p);
      }
      if (typeof p !== "object" && typeof p !== "function") {
            throw TypeError();
      }
      function f(){};
      f.prototype = p;
      return new f();
}
var parent = {a: "I am parenting"};
var child = inherit(parent);

Lets understand inherit function line by line.

if (p == null) {
      throw TypeError();
}
If parameter passed is null then Exception will be thrown.

 if (Object.create)
      return Object.create(p);
}
If Object.create() is already defined than use it to create object and return it.

if (typeof p !== "object" && typeof p !== "function") {
      throw TypeError();
}
If parameter provided is neither an object nor function than also throw a TypeError. But if are using this condition than why do we need first condition for checking null value? That's because typeof null equals an object which is obviously weird (you can explore this more on my other post Reasons Why JavaScript is weird).

function f(){};
f.prototype = p;
return new f();
Here function f is an empty function which we will use as an constructor. We know that each function and object has inbuilt prototype property. One interesting fact about prototype property of constructor is that, all the objects created through constructor will inherit from the prototype property of that constructor.
Taking advantage of this fact we are setting prototype of constructor to the p (parent we have passed as parameter to inherit function). Now with new f(), we will be able to create an object and will return it.

We were able to pass the second parameter to Object.create() method in order to initialize the newly created object but with inherit method we can not do that.

Now that we have good understanding of Objects and prototype, we can jump to the Classes and Inheritance or say third way of creating an object.

As we already know that Class is just an collection of objects which inherits from same prototype object, we can create class by creating an prototype from which objects can inherit. In order to do that we can use our inherit() function defined above.

var c = function(initial, end) {
      var f = inherit(c.methods);
      f.initial = initial;
      f.end = end;
      return f;
}
c.methods = {
      sharedMethod: function() {
            console.log("I will be shared among all the objects.");
            console.log(this.initial + " " + this.end + " initial and end parameters are not shared among all objects. ")
      }
}
var obj = c(1, 9);
obj.sharedMethod();

Lets understand above code line by line.

var c = function(initial, end) {
}
Here c function can be considered as an class. This class takes 2 parameters initial and end.

var c = function(initial, end) {
      var f = inherit(c.methods);
}
Here Class c is using inherit method to set c.methods as an prototype of f object.

var c = function(initial, end) {
      var f = inherit(c.methods);
      f.initial = initial;
      f.end = end;
}
After creating an object f whose prototype is c.methods, we are setting variables of f object. This variables will not be shared among all the objects.

c.methods = {
      sharedMethod: function() {
            console.log("I will be shared among all the objects.");
            console.log(this.initial + " " + this.end + " initial and end parameters are not shared among all objects. ")
      }
}
Here c.methods will act as an prototype object which is getting inherited by all the objects of class c. Methods defined inside c.methods will be shared among all the objects of class c.

Classes and Constructors:


We have explored way to create Classes using prototype. Now we will create a class using constructors. Constructors can be defined as public face of Class as classof() property for an object returns the constructor name from which that object is created. But constructors should never be confused with class. Above method to create an class can be modified using constructors.

var C = function(initial, end) {
      this.initial = initial;
      this.end = end;
}
C.prototype = {
      sharedMethod: function() {
            console.log("I will be shared among all the objects.");
            console.log(this.initial + " " + this.end + " initial and end parameters are not shared among all objects. ")
      }
}
var obj = new C(19, 20);

This way seems pretty simple..Right?? Lets explore this too..

var C = function(initial, end) {
      this.initial = initial;
      this.end = end;
}

Here function c is constructor function. this refers to the newly created object. We know that each function has its prototype property defined. So,

C.prototype = {
      sharedMethod: function() {
            console.log("I will be shared among all the objects.");
            console.log(this.initial + " " + this.end + " initial and end parameters are not shared among all objects. ")
      }
}
We are assigning an object to C.prototype and that object has defined sharedMethod() function which will be shared among all the objects created from C constructor.

But, prototype property has some predefined variables set. If we will directly assign our object to C.prototype then we will end up loosing all predefined properties. So best practice is to set property of C.prototype like this:

C.prototype.sharedMedhod = function() {
      console.log("I will be shared among all the objects.");
      console.log(this.initial + " " + this.end + " initial and end parameters are not shared among all objects. ")
}

Coming to the predefined properties of prototype object..What is it? Any clue??? Well it is constructor property that matters.

C.prototype = {
      constructor: C
}

Whaaattt???? Well yes.. prototype property of C has another property constructor which points to the C constructor itself.
It has another property __proto__ which will point to its prototype object. In our case it will be Object object.

Lets play with it,

var F = function() {};      // This is a function object.
var p = F.prototype;      // This is the prototype object associated with it.
var c = p.constructor;      // This is the function associated with the prototype.
c === F                        // True.

I hope this post was helpful for you to understand Classes in JavaScript. ECMAScript 6 has easy way to define classes using class keyword. We will cover this also shortly.

1 comment:

Unknown said...

Very interesting.