Although JavaScript is a Class-Free language, it supports objects creation, overriding properties/methods and inheritance. In this post, we will explore the concepts of object creation and inheritance.
In JavaScript, Objects can be created in three possible ways:
- An object as literal
- Using the function constructor
- Using the Object.Create method
Object as literal
A simple object Student - as an object literal - can be created as shown in the listing below:
var Student = { name:"dj", age:32, Father: {'name':'Ram','occupation':'service' }, Subjects: [{ name:"Physics", marks:89 }, { name:"Chemistry", marks:95 }] };
Above we have created an object called Student. There are three types of properties attached to Student: simple properties like name and age, complex properties like “Father”, and an array property called Subjects. We can read properties as shown in the listing below:
console.log(Student.Father.name);for (var i in Student.Subjects) { console.log(Student.Subjects[i].name); }
We can also have a function serve as the property of an object, which is known as the method. So let’s say we want to attach a method “Speak” to the Student object. We can add the Speak method as shown in the listing below.
var Student = { name:"dj", age:32, }; Student.Speak =function (message) {var finalMessage =this.name +" has said :"+ message; console.log(finalMessage); }; Student.Speak("I am the best");
On calling Speak function as method, we will get output as shown in the image below:
There are some important points about the Speak method to remember:
- Properties can be added to an object at any time; a property can be added to an object after its creation too. For example, we added the Speak property later to Student object, rather than at the time of object creation.
- In the object’s method, the object is defined by value “this”. That is why we are able to print the name of the Student using this.name in the method.
- Calling a function as method is known as “Method Invocation Pattern”
In the above example, we are calling the Speak method on the object “Student”. So the value of this inside the Speak method is the Student object.
If we want to pass some other object as the value of “this” in the method, we can use the apply or call function. For example, we have one more object called Parents and,
- We are calling the Speak method of the Student object directly and the value of “this” in the Speak method would be Student.
- We are passing Parent as the value of “this” in the Student object’s Speak method. We are using the apply function to call the Student object’s Speak method and passing the Parent object as the value of this.
We can perform above tasks as shown in listing below:
Student.Speak("I am the best");var Parents = {'name':'Ram' } Student.Speak.apply(Parents, ["I am the Best"])
On running we will get the output as below:
As you may infer from the output, the value of “this” in the second line is Parent, hence as output we are getting Ram for the value of name.
Using function constructor
The second way of creating an object is by using the function constructor. When we call a function using the new operator, the function becomes a constructor and returns the newly created object. In the function constructor, the current object is represented by “this”.
function Person(name, age) {this.name = name;this.age = age;this.message =function () { console.log(this); console.log(this.name +" is "+this.age +" years old !"); } }; var person1 =new Person("dj", 32);var person2 =new Person("mj", 34); person1.message(); person2.message();
In the above listing, we are calling the Person function using the new operator, hence, the Person function behaves as a function constructor and returns a new object which is being saved in person1 and person2. We are then calling the message method on the person1 and person2 objects.
On running the above snippet, we will get the output as shown in the image below:
One point worth noticing in the above output is that each object has its own message method. In many cases, you may not want that. Perhaps, you may want the message method shared across objects with the value of “this” set to the object calling the method. This can be done by attaching the message method to the prototype of Person.
function Person(name, age) {this.name = name;this.age = age; }; Person.prototype.message =function () { console.log(this); console.log(this.name +" is "+this.age +" years old !"); } var person1 =new Person("dj", 33);var person2 =new Person("mj", 34); person1.message(); person2.message();
What is happening here? On executing the above snippet, you will find that the message method is not getting copied for each object, and it is part of the prototype of the Person constructor function. When running the above snippet, you’ll get the output shown in the image below:
Function constructors enable us to have private properties in the object. We can create a private property in two possible ways –
- Using the var instead of this to create a property
- Using the REVEALING PATTERN.
A private property can be created using var as shown in the listing below-
function Person(name, age) {var prvvar ="i m private"this.name = name;this.age = age; };var person1 =new Person("dj", 33);var a = person1.prvvar; console.log(a);
Here, the expected value of prvvar outside the Person function is undefined.
Another way a private variable can be created is by using the revealing pattern. We can create private properties by explicitly returning public properties and public methods from the constructor function as shown in the listing below:
function Person(name, age) {this.name = name;this.age = age;return { pubvar:this.name +" is "+this.age +" years old" } };var person1 =new Person("dj", 33);var a = person1.pubvar; console.log(a);
Let us see what is happening here. We are explicitly returning pubvar as public property. In above snippet, name and age properties become private variables and accessing them outside the Person function will return undefined.
Inheritance in JavaScript
JavaScript supports prototype-based inheritance so instead of class, objects inherit each other. Before we learn about inheritance, let us have a look at a prototype in JavaScript. In JavaScript, a prototype behaves differently for functions and objects.
What is a prototype?
Every function has a prototype property. Let us consider a function as below:
function foo(name) {this.name = name };var fooPro = foo.prototype; console.log(fooPro);
As output, we will get an empty object as the prototype value of the function.
A function prototype is the object instance which eventually becomes the prototype of all the objects created using that function constructor.
Let us go ahead and create objects using the new operator for the foo function. In the below listing, we are creating two objects and then printing __proto__ value of both the objects.
foo.prototype.age =30;var fooobj1 =new foo("mj");var fooobj2 =new foo("dj") console.log(fooobj1.__proto__); console.log(fooobj2.__proto__); if (fooobj1.__proto__ === foo.prototype) { console.log("true"); }
You will find that __proto__ value of both objects are the same. Also one important observation could be __proto__ value of objects are equal to the prototype value of the function. The expected output would be as shown in the image below
By looking at the above example we can say that the function prototype is an object instance which will become the prototype of all the objects created using that function as a constructor.
On the other hand, objects do not have prototype values, instead, they have __proto__ value. Let us consider below example:
var foo ={}; console.log(foo.prototype); console.log(foo.__proto__);
We are printing the prototype value of foo and also __proto__ value of foo. For prototype value, JavaScript will return undefined, whereas for __proto__, it will return an empty object. The expected output would be shown as seen in the image below:
Each object inherits an object. Object __proto__ value is set to the object instance from which the object is inherited.
Using __proto__ for inheritance
Some important points about JavaScript inheritance are as follows
- JavaScript supports prototype based inheritance
- In JavaScript, objects inherit each other
- The Parent object is also known as the prototype of the child object in JavaScript.
- In JavaScript inheritance is implemented through (for objects) special property __proto__
- To access a property, JavaScript first searches objects, if it does not find it, it searches that in __proto__ property of object. In modern browser __proto__ property is also known as prototype property.
Let us start with two very simple objects
var animal = { eats:true, canRun:function () { console.log("yo can run!"); } };var dog = { canbark:true };
Here we have two objects: animal and dog. The object animal has two properties – eats and canRun. The object dog has one property: canBark.
Let us see how object dog can inherit the object animal. Using the _proto__ property, dog can inherit animal as shown in the listing below:
dog.__proto__ = animal;
console.log(dog.eats);
dog.canRun();
By setting __proto__ property to animal, we inherited animal to dog. As you notice in the above example, now on the dog object, we can access the eats and canRun properties.
JavaScript interpreter searches for the property in two steps.
- First it searches for a property in the current object. If it finds it, it uses it.
- If it does not find a property in the current object, it searches for the property in the __proto__ values of the object until the __proto__ value becomes null.
Working with “this” in inheritance
Regardless of the value of __proto__, JavaScript always assigns the current object as the value of “this”. To understand it, let us modify the previous object,s animal and dog.
var animal = { eats:true, canRun:function () {this.isCute ="yes" } };var dog = { canbark:true };
As you notice, we have two objects: animal and dog. In the animal object’s method canRun, we are creating a property isCute and attaching that to “this” or the current object. Let us go ahead and inherit animal in dog.
dog.__proto__ = animal; dog.canRun();var flag = dog.hasOwnProperty("isCute"); console.log(flag);
As you rightly noticed, using the hasOwnProperty() method, I am checking that whether isCute is property of the dog object or not. We will get output of true. This happens because before calling the canRun() method , JavaScript assigns dog as the value of “this”.
The JavaScript method hasOwnProperty() returns true for the object’s own property and false for the properties of the prototype. In this case it would return true, because isCute has been attached as the property of the dog object.
Let us take one more example to explain how value of “this” gets assigned. In the previous example, we used __proto__ to create the inheritance. In this example, we will use the Object.create() method to clone an object. Later in the post, we will cover more about Object.create().
Let us consider we have an object foo as shown in the listing below:
var foo = { c:8, add:function () {this.c =this.c +1; } };
Object foo has two properties, c and a method add. In the add method, the value of the c property is getting incremented by 1. Next let us go ahead and create another object by cloning object foo using the Object.create() method.
var koo =Object.create(foo); koo.c =99; koo.add(); console.log(koo.c);
What is happening in the above code snippet? We are creating the object koo by cloning the object foo. So object koo has all the properties of foo. We are setting the value of property c and then calling the method add on the koo object. As we discussed in the previous example, regardless of the value of the prototype, the value of “this” is always set to the object before the dot in calling the method. So in this case, the value of “this” is set to the koo object. The expected output of the above snippet would be 100.
With the new ECMA specs, __proto__ is getting depreciated, and all browsers support prototypes. We can use a prototype instead of __proto__ to create the inheritance. Keep in mind that a prototype only works with function constructors, and it is widely supported in all the browsers.
Let us see how a prototype can be used to create an inheritance. Let us start with a function Employee as shown in the listing below:
function Employee(name) {this.name = name; }var e =new Employee("dj");
We are calling the Employee function as the constructor using the new operator to create an object e. While executing the constructor, the value of the name property is set to value dj. Next let us go ahead and create another constructor: SuperEmployee.
function SuperEmployee(sal) {this.sal = sal; } SuperEmployee.prototype = e;var se =new SuperEmployee(5000); console.log(se.name);
The SuperEmployee function prototype is set to object instance e. The object instance of the SuperEmployee constructor is going to inherit the name property of e object instance. We can also set the prototype of SuperEmployee as shown in listing below:
function Employee(name) {this.name = name; } Employee.prototype.age =30;function SuperEmployee(sal) {this.sal = sal; } SuperEmployee.prototype = Employee.prototype;var se =new SuperEmployee(5000); console.log(se.age);
In the above listing, we are setting up the prototype value of the SuperEmployee function to the Employee Prototype. In this way, SuperEmployee will inherit all the properties of the Employee prototype.
Inheritance using Object.create()
In JavaScript, we can create an object by using the Object.create method as well. I find this to be the simplest way of creating an object.
var foo =Object.create(Object.prototype); foo.name ="dj"; foo.age =33; console.log(foo.name);
In the above snippet we have created an object foo, and then dynamically added two properties: name and age. “dj” will be the output, as shown in the image below:
Some important points about Object.create() are as follows:
- This method takes two arguments .The first argument is the prototype of the object to be inherited, and is the required argument.
- The second argument is the optional argument, and adds new properties in the newly created object.
- The first argument can be null, but in that case the new object will not inherit any properties.
- To create an empty object, you must pass the Object.prototype as the first argument.
We can use Object.create() to create an object inheriting another object instance. For example, let us say we want to inherit foo object in koo object.
var koo =Object.create(foo); koo.grade ="a"; console.log(koo.name); console.log(koo.age); console.log(koo.grade);
While creating the koo object, we are passing foo object in Object.Create. So koo object will inherit all the properties of foo object. JavaScript will make copy of foo object such that can be assigned as prototype value of koo object.
Putting it all together to create a simple prototype Inheritance chain
So far we have learned about function constructors, object literals, the __proto__, prototype, and Object.create(). Now let us put all them together to create a help function which will accept two objects and create an inheritance between them. We can create that function as shown in the listing below:
var inherit =function (child, parent) { child.prototype =Object.create(parent.prototype); }
To create the inheritance we are setting the prototype of the child as the prototype of the parent function. Now let us go ahead and create a simple function constructor, foo, and create the object instance of that.
var foo =function () {this.name ="class foo"; } foo.prototype.print =function () { console.log(this.name); }var f =new foo(); f.print();
If you are following along the discussions you know f is an object instance of foo and as output we will get an output of class foo. Next, let us go ahead and create another function, fooChild, and inherit it from the foo function using the inherit function we created above.
var fooChild =function () {this.name ="foo child";this.surname ="I'm the child of foo"; } inherit(fooChild, foo); var fchild =new fooChild(); fchild.print();
In the above code snippet we are inheriting foo in fooChild and also calling the print method of foo on the object instance fchild of fooChild constructor function. This will print the name property of fooChild as shown in the image below:
To print the surname property we need to override the print method in fooChild function, as shown below:
fooChild.prototype.print =function () { foo.prototype.print.call(this); console.log(this.surname); }
After overriding, when you call print method on fooChild object, it will print both name and surname values.
In this way we can create a simple inheritance chain in JavScript. Putting it all together, the inheritance chain code will look like this:
var foo =function () {this.name ="class foo"; } foo.prototype.print =function () { console.log(this.name); }var f =new foo(); f.print();var fooChild =function () {this.name ="foo child";this.surname ="I'm the child of foo"; } inherit(fooChild, foo); var fchild =new fooChild(); fooChild.prototype.print =function () { foo.prototype.print.call(this); console.log(this.surname); } fchild.print();
And the expected output would be as follows:
Conclusion
In this post we started with constructing simple objects and ended by creating a function to create a prototype inheritance in JavaScript. We covered the following topics in this post:
- Object literal
- Function constructor
- Revealing pattern
- Understanding the value of “this”
- __proto__ property of object
- Prototype value of function
- Inheritance using __proto__ and prototype
- Object.create() method for object construction
- Creating an inheritance chain
I hope you like this post and find it useful. Have something to add? Leave a comment! Thanks for reading.