What are constructors?

Constructors in JavaScript are simply functions used to create objects. They act as templates for creating similar objects. (by similar we mean sharing the same property names).

In JavaScript we have many predefined constructor functions like Number(), String(), Boolean() that can be used to create objects for specific purposes. However these predefined constructors may not be that much useful as self-constructed constructor functions which you create yourself.

But why constructors?

This is a likely question that someone new to constructors might ask? To answer it let's first draw a scenario.

Suppose there is an online library with a ton of books on tutorials. You are given the task to store the details of the books such as name, pages etc in a JavaScript program using objects. What will be your choice for this task? Well you may most likely think of creating seperate objects for each book.

Something similar to this:

var book1 = {name: "Web Designing Guide", genre: "General Knowledge", pages: 120, id: 3156};
var book2 = {name: "JS Skills", genre: "General Knowledge", pages: 500, id: 1052};
/*
var book3 = {name......
var book4 = {name......
var book5 = {name......
var book6 = {name......
*/

This is certainly alright, but not at all efficient. We are merely copy pasting the same object statement, down the script, with just changed property values. What if we wanted to add a new property for all books or get the total number of books added, given that they are over 100? Clearly a nightmare!

We can definitely make this efficient and we should. Programmers have to value program efficiency and scalability and this is what makes them different from other programmers. Coming back to the topic, we have a simple workaround for saving our time copy pasting objects and that is constructors. Let's dive right in.

Constructing a constructor

Creating a constructor is just like creating a function. After all constructors are functions.

The whole idea around constructors is that when objects, in this case books, share the same class (like lions, cheetahs, cats, dogs share the class animals) and hence the same characteristics they can be modeled in a template. This model template is the constructor and has all the things in it that we would need for the objects.

So let's create a constructor function Book for our task:

function Book() {
    this.name = "";
    this.genre = "";
    this.pages = 0;
    this.id = 0;
    this.displayInfo = function() { return "Name: " + this.name + " Genre: " + this.genre + " Pages: " + this.pages; }
}

What we are doing here is simply initialising the properties needed for our books like name, genre. Nothing shall be new here for you except for the this keyword.

this refers to the object on which properties and methods are being set.

You will understand this in just a while. Now from the above code we have laid out our constructor function i.e our template for objects but not yet created one object from it. Let's even do that with the following statement.

var book1 = new Book();

The new keyword creates a new instance from a given constructor. An instance in JavaScript is an object created from a constructor.

And we have succesfully created a new book object from the Book() constructor. However the object has not yet been filled with real values i.e we have properties like name, pages initialised to some default values, not to the actual values of the book.

See the following code in which our pages property logs with its initial value 0.

console.log(book1.pages) // 0
// this is the initial value assigned in the constructor

So let's even do that using the way to change property values of an object after it has been created, as discussed in the previous Creating Objects chapter.

book1.name = "Web Designing Guide";
book1.genre = "General Knowledge";
book1.pages = 120;
book1.id = 3156;

We have added information for one book successfully in our program and we can do so to add as many books as we want. But if you notice one thing over here that to add a book object we have to write a lot of lines of code unnecessarily - first creating an object and then filling each property seperately. There is a simple work around for this and you might know it from the functions unit. Can you remember? It is arguments.

Arguments and constructors

Constructors are JavaScript functions and hence can avail all the advantages normal JavaScript functions can do. Arguments are no exception.

We can use arguments to pass values to a constructor when it is called with the new keyword and then directly assign them to given properties of the created object.

function Book(name, genre, pages, id) {
    this.name = name;
    this.genre = genre;
    this.pages = pages;
    this.id = id;
    this.displayInfo = function() { return "Name: " + this.name + " Genre: " + this.genre + " Pages: " + this.pages; }
}

var book1 = new Book("Web Designing Guide", "General Knowledge", 156, 3156);

console.log(book1.name); // Web Designing Guide
Here in line 9 we call the constructor and pass it some values. Those values get assigned to the properties of the book1 object in the constructor definition. This approach can save time and the extra lines wasted otherwise on changing properties manually.
For the displayInfo method we have not changed this.name to name or this.genre to genre in line 6 to keep the method scalable. With this.name the objects property will be fetched each time the method is called but with only name the value will be replaced by the variable's value at the constructor's call. This means that with this.name the displayInfo method will display latest data.

The constructor property

Objects created from constructors have a constructor property on them which points to the function definition of their constructor. For our book1 object it looks like this.
console.log(book1.constructor); // ƒ Book(name, genre, pages, id) { ....
Since the constructor property holds the constructor function's definition we can use it as a method to create another book object. This approach is exactly same as calling the constructor itself.
var book2 = new book1.constructor("JS Skills", "General Knowledge", 500, 1052);
// Same as
// var book2 = new Book("JS Skills", "General Knowledge", 500, 1052)

console.log(book2.name); // JS Skills
console.log(book2.displayInfo()) // "Name: JS Skills Genre: General Knowledge Pages: 500"

When will you need this?

When you want to create instances out of a constructor but don't know its name, and have at least one object instance from it already. You can also use this property to check for a JavaScript array.

Recall from the Arrays Basic Concepts chaper, we saw two ways to check for the array data type in JavaScript. The second of the two was utilising the constructor property and we claimed to explain it in the Objects unit. It's time to explain that code now!

var arr = [1, 2]; // an array

console.log(arr.constructor.toString().indexOf("Array") !== -1) // true

The most important part of this code is the statement in line 3 inside the pair of parentheses as illustrated below that does all the magic. Well it is not magic!

arr.constructor.toString().indexOf("Array") !== -1; // returns true
  1. First arr.constructor returns the definition of the constructor of arr. The constructor for arr is Array().
  2. Then toString() converts the definition into a string.
  3. And finally we find if the word "Array" exists in this string.

Now despite the fact that we have not created arr using the Array() constructor it still has the constructor property available on it. But why?

Simply because all data types in JavaScript inherit properties from their prototype. The prototype of arr is Array.prototype and this object has a constructor property.

More on prototypes later.

Just think of it this way that every data type is converted to its respective object using its respective constructor.

A constructor acting like a subclass

Uptil now we have seen how to create objects from a given constructor. We encapsulate all the necessary properties and methods inside the constructor and then create objects from it. The constructor acts like a class. But what about if we want a constructor to act like a subclass, for example the subclass Coding for the class Book i.e any changes to Book will also be applied to Coding? Didn't understand? Let's explain it.

We want a class Coding to be built on top of  the class Book. What this means is the following.
Class and Subclass link
Instead of defining the function Coding like this:
function Coding(name, genre, pages, id, rating) {
    // We are defining the properties again
    this.name = name;
    this.genre = genre;
    this.pages = pages;
    this.id = id;

    this.rating = rating;
}
..we want it to copy the function  Book so that whatever change we make to Book, also applies to Coding. We want Coding to EXTEND Book. This can be achieved using the call() method available to functions.
function Coding(name, genre, pages, id, rating) {
    Book.call(this, name, genre, pages, id)
    this.rating = rating;
}
What does this method do?
The call() method simply calls the function Book in the current context of Coding. Without call() Book would execute in the global scope and its this would be the window object. Its first argument is the value of this it would provide to the calling object, in this case Book.

And now let's show you the magic. We have changed the name property in the constructor Book to include a string Testing before it. Then we create an object instance f1 from Coding and log its name. See the surprise!
function Book(name, genre, pages, id) {
    this.name = "Testing " + name; // value changed to include "Testing" before it
    this.genre = genre;
    this.pages = pages;
    this.id = id;
    this.displayInfo = function() { return "Name: " + this.name + " Genre: " + this.genre + " Pages: " + this.pages; }
}
function Coding(name, genre, pages, id, rating) {
    Book.call(this, name, genre, pages, id)
    this.rating = rating;
}

var f1 = new Coding("JavaScript Is Best", "General Knowledge", 500, 1068, 3.5);

console.log(f1.name); // Testing JavaScript Is Best
We altered Book but the change got heard in Coding too and we get the name preceded by Testing.

And we are finally done with constructors!

In conclusion

Constructors are not an easy topic to deal with in programming and so it should not be surprising if you didn't get all of this at first glance. Sometimes certain concepts in programming don't just come at glances, instead they come only at practice!

Definitely learning constructors is difficult, but not impossible. Aim for it and you will surely understand it! We have some exercises for you to practice to help you in understanding this topic better.