Saturday, March 16, 2013

Understanding Constructor Function and this Keyword in Javascript


Back in 2006 I wrote a post on using constructor functions in Javascript to create objects. This post builds on that post, expounding it a little bit further.

By definition, a constructor function is a normal Javascript function. Nothing more, nothing less. What makes a function a constructor is how it is used. When a function is used in such a way that it can create an object, by calling it with Javascript's new operator, then it becomes a constructor function.


This means all and any function you have in Javascript can be used as a constructor function.

var Person = function () {
  console.log("I am a function");
}
We can call this function normally:
Person(); //prints to the console "I am a function"
console.log(typeof Person) //prints to the console ‘function’
So let’s now use this function as a constructor and create an object:

var bond = new Person();
Now let us confirm that bond is indeed an object:

console.log(typeof bond) //this prints "Object"
Now that is all about Constructor functions.  It is as simple as that: A function that is the same as your normal Javascript function but can be used to create objects.

But you would notice that the object created above is empty (without properties) and maybe of little or no use. Compared to the example given in my previous post, which had properties. 

So how do you actually make an object with some already set properties at creation? Before we go ahead and look at this, its worth mentioning a characteristics of functions in Javascript (apart from this fact that they can be used to create objects).
Functions are first class citizens in Javascript and also Functions can have properties just as objects! Yes just like you add properties to an object, you can do same to a Javascript function.



So we already have a function Person we can add properties to it! for example:

Person.createdBy = "Dade";
Person.sayWhoCreatedYou = function () {
   console.log(Person.createdBy);
}

To see this really work, when we call Person.sayWhoCreatedYou() you get "Dade" printed to the console!

Do not sweat it that much if this feels funny right now, especially if you are coming from a language that does not treat functions as a first class citizens. This was mentioned now as it would help understand another interesting concepts in Javascript: Prototypes. Right now, just know that in Javascript, functions can have properties. 

That being said, let us now build on the knowledge we have so far and create a more useful object, with properties and methods using Constructor functions.

But in other to do so, there is yet another important thing we need to understand: The concept of this keyword in Javascript. Understanding this in Javascript would help shed more light to what actually goes on when an object is created via Constructor functions and how properties are added to the object.

This in Javascript

In a language like Java, this keyword refers to the current instance of a particular object. And in Java, the method defined in a Java Class is bound to, or belongs to a particular instance object that is created from that class.  In Javascript, things are a little bit different. Javascript is not a Class based programming language so do not except the concept to be the same as in Java (or similar Class based language: C# etc).


I like to think of this keyword in Javascript as a context. The context points to an Object still, but the object it points to can easily be changed. This means that I can have one function in which I have this keyword, and depending on how I call the function, the this can refer to the window object of my browser, Dom object, or any arbitrary object, even objects I define myself!

Yes, the mental mode to change when thinking about this in Javascript is that it really has no strong relation whatsoever with where it was defined! This is not the case in Java. In Java, when you use this keyword in a method, you know you are referring to any object that is created from that class. Not so in Javascript. In fact I like to think if this in Javascript, not as this object, but any of that objects!

So when we have an updated Constructor functions that looks like this:
var Person = function () {
  this.name;
  this.theTimeCreated = new Date();
  this.sayMyName = function () {
  console.log(this.name);
  }
}
What does this then refer to? 

We can never tell by just looking at the function definition! We can only tell if we know where it is called! Again, I think of this as a context, a context which points to an object but which easily changes depending on how the function is called.

If you call Person() like you normally call a function and not like a Constructor function with the new keyword, this would refer to the window object! Yes it would! So it would be as if in the definition you have is this:
var Person = function () {
  window.name; //does nothing.
  window.theTimeCreated = new Date();
  window.sayMyName = function () {
  console.log(window.name);
  }
}

Wait a minute. Look at the code again...what did you just do by calling Person(). You just added properties to the window object! ouch! Not good! You should not be doing this!

To confirm that the window object has indeed been updated, you can console log window.theTimeCreated() and you would get the date you ran the function! If you also run window.sayMyName() the name of the window (if set) would be logged to the console!This is really dangerous as you can unknowingly change things that should not be changed in the window object! So it is important to actually have a good grasp of how this behave in Javascript.

Now to see that we can easily change the context of the this keyword lets create another object that has a name property:
var anotherObj = {
   name : "My name is Bond...James Bond!"
}
And now do this:
anotherObj.personFunction = Person;
Or better still just define the new personFunction in one step:
var anotherObj = {
   name : "Yay! I am the new object context!",
   personFunction : Person
}
Basically what you just did is to make the Person function part of the anotherObj and this would change the context of the this used in the Person function. So what you have very much look like this
   var anotherObj = {
   name : "My name is Bond...James Bond!",
   personFunction : function () {
           anotherObj.name;
           anotherObj.theTimeCreated = new Date();
           anotherObj.sayMyName = function () {
                      console.log(anotherObj.name);
                 };
           }
}
So this now refers to anotherObj so when you call Person() via anotherObj like this anotherObj.personFunction() this time around the window object is not touched, but the object that would be in context would be anotherObj

To confirm this, console log anotherObj.theTimeCreated() and you would get the date you ran the anotherObj.personFunction() function and If you also run anotherObj.sayMyName(), you see "My name is Bond...James Bond!" because the object you are working in its context now is anotherObj and it has a property name with the following value.

So how does all this come together and relates to Constructor Functions?

Like this:

The new Keyword when used to call a function would automatically changed the this defined in that function to refer to the new Object it would create! And this is how you can have properties defined in the Constructor function that would be made to become part of the object created with the Constructor function.

That is to say, if I want to use Person function to create a shiny new object. I'll do:

var shinyNewObj = new Person();

And viola, my shinyNewObj now has all the three properties defined in the Person function.

You can also have the Constructor function take arguments, which can be used to set initial values of properties of the object. And this is how the Constructor function in the previous post worked. 

That is:
var Webdeveloper = function(identity,location,technologies,blog)
{
   this.identity = identity;
   this.location = location;
   this.technologies = technologies;
   this.blog = blog;
}

And can be used like this:
var wd = new Webdeveloper('Olabini','New York','JRuby', http://olabini.com/blog)

4 comments:

Mayank Gupta said...

Thanks for such a nice Explanation

Anirudh Chadha said...

This is the first time constructor functions have TRULY come together for me. It's all about the 'this', and they've never been described that way to me before. Thanks!

qmn said...

Come from Java, and your post helps me really understand what is javascript constructor and "this" keyword.

Many many many thanks!

Akshay Vijay Jain said...

Many Many Thanks Again.
You have written informative content for welfare of other.