Introduction
Variable scoping has always been a part of every programming language. Whether we are using a class based object oriented language (e.g. Java/C#) or a class-less object oriented language, scope has a very important role to play.
What scope defines?
In easiest terms, scope defines the visibility of any variable/data. In JavaScript, you can define a piece of code (function/method) globally or you can keep it within an object and expose it for public use. The keyword 'this' has a special significance when it comes to JavaScript. Other languages also use the 'this' keyword but it needs some serious attention if you are trying to use or understand it in JavaScript world.
Background
JavaScript is no more a client-side-only language. This means that it can be used to write both client side (within the browser) as well as Server side code(Node JS). In this article, we will be talking about the behavior of 'this' keyword only when JavaScript is used as a client side language i.e. when it is running within a browser environment. I will have another article for the story of 'this' when JavaScript is used in server side environments like Node.
Let us start with some easy cases and we will further move to more complex ones where 'this' might go crazy if we don't exactly know what's going on.
So first up:
'this' when used in Global Scope
Lets take a look at this code below:
and here are the results...
So when 'this' is not used inside a object or function or method, then this refers to a global "Window" object. Everything in the browser is contained within a window object. You can think of "window" object as the parent of everything in JavaScript. The complete DOM(document object model) including your <html> and <head> and <body> tags are a part of document object and document object is also a child of the global "Window" object. You can check this by doing window.document (or this.document in this case where 'this' refers to the global window object)
Just to remind you we are talking about JavaScript only in browser environment where 'this' refers to the window object in global scope. We are not talking about server side JavaScript in this article.
Another example of 'this' in global scope is when you declare a global variable. A global variable is a variable declared outside of an object or function or method in JavaScript. For instance, look at the code below:
and the results...
We do not explicitly have to use the 'this' keyword. You can directly refer to the variable as well. We used the 'this' keyword to refer to the variable in order to demonstrate the fact that when we declare a variable in global scope like the above, the variable automagically gets added to the global object i.e. the Window object. What it means is now the variable 'employeeCount' is a variable of the Window object. Proof? I tried looking in the console... doing window.employeeCount , see below what I got...
[Extra Notes: It is not encouraged to have your own variables in the global space in JavaScript. In fact it was one of the worst things you could do while writing JS code. All the examples in this article are for demonstration purpose. You may want to read about 'Module' pattern and how to avoid declaring your stuff in global scope in JS.]
[ Extra Notes: You might have noticed me writing "functions or method" in this article. Why? Because functions and methods are two different things in JavaScript, really? Yes they do refer to two different code blocks. We will see it soon in this article ]
Anyways, next up:
'this' when used inside a function
Let's declare a function in the global world, consider the code below:
So when we called the AddEmployee( ) function in the end, here are the results...
Oo boi ! Were you expecting something different ? In case you are coming from a different OO language may be from a class based OO language like Java/C#, you might expect that the 'this' keyword will have its own meaning in the above scenario. I too, expected the same thingy that 'this' will have a personal scope when used in a function but this guy 'this' is a lil crazy in JavaScript. So what happened? 'this' still refers to the global window object. This time, we have added 2 things to the global scope(to the window object). You gotta make a guess! Oo yes I know you got it... 1) employeeCount variable and 2) AddEmployee( ) function. Both are now a part of the window object and can be called by referring to the window object. Proof? Here it is...
'this' when used inside an Object Literal
In JavaScript we use literals to store values. Among many, the most literals are Array Literals and Object Literals in JS. We have variables to store simple values but when it comes to having a variable which contains a several other variables inside of it and you might want to have some functions too which define the functionality/behavior of that object, you'd want to use Object Literals.
Lets consider a example below
In the above code, Employee object literal has a property 'headCount' and a method named 'AddEmployee'. This is not a function but is called a method. When a piece of code in an anonymous function is given to a property in a object literal, it is called a Method. I know you got it, this is the difference between function and method in JS.
When you call a method in JavaScript, the value of 'this' is set to the object on which the method is called.
In this example, AddEmployee( ) is called by reference of Employee object , so 'this' inside of AddEmployee( ) method refers to the Employee object. Since Employee object has a headCount property, it shows that up.
If I call the Employee.AddEmployee( ) method more than once, this.headCount will still refer to the same headCount within the Employee object literal and will keep on incrementing it. I did it in the console to save some time, please check it below
[Some Extra Adventures : In case you really want to dive deep, remove the 'this' keyword in the line this.headCount++ and see what happens. You will definitely find out what happens but a clue for you is that 'whatever' will happen because the function will try to look that up within the global scope', let me know in comments if you try !]
So far so good, let's dive into some more complex scenarios to understand what 'this' has to offer in JavaScript.
'this' when used in a Constructor Function
Object literal as we saw is a way of constructing object on the fly in the JavaScript. However if we want to create multiple objects of the same type in JavaScript, we make use of constructor functions. It is kind of similar to classes in other languages, "kind of" but not quite.
How to make use of constructor functions to create objects?
2 Steps:
a) Write a simple function
b) Call the function with a 'new' keyword, store the reference in a variable
So let's look at an example:
And guess what ! We are in a different world now. Calling a function with the 'new' keyword changes the story of 'this' !!! Yayyy! Finally we see something different. So what happens? When you call a function with a 'new' keyword (usually to create an object), 'this' is set to an empty object. Proof? Check the results of the above, below
Now 'this' does not refer to the global window object. 'this' now has its own world and it does not have to deal with the global scope. Oo boi I am excited !!! are you?
Let's add some properties and functions into this constructor function:
When above code runs and we call the constructor function with 'new' keyword, everything runs except the function AddEmployee( ) since we haven't called it yet. Next, we call the function AddEmployee( ) by referencing the oEmp object of type Employee. As I said before, constructor functions are used in JavaScript to create objects of a similar type. We will see that shortly. Okay so what's the result of above code?
The value of 'this' in the AddEmployee( ) method is again determined by the caller. The caller here is oEmp which is an object of type Employee, hence 'this.headCount' refers to the headCount defined in the Employee constructor function. If you see the above result closely, you can see that Employee is once an empty object and when after a adding a property and a function, Employee object is no more an empty object. It contains the property and function we defined in it. We can call the AddEmployee( ) function with reference to the oEmp object as many time as we want, to save some time, i did this in console again...
How about we create more than 1 object by using our constructor function.
When we run line 23, the 'this.headCount' within AddEmployee( ) belongs to HumanResource object. Similarly, in line 26, when AddEmployee( ) is called, the value of 'this.headCount' belongs to Sales object alone.
[You may want play on the console by calling both HumanResource.AddEmployee( ) and Sales.AddEmployee( ) as many times as you want and check to see there counts are separate. Both have their own personal 'this']
In short, to keep track of 'this' while using constructor functions, you need to check on which object the method was called within which you are using the 'this' keyword.
'this' when a global function is called from within a method in a constructor function
The ride so far was smooth, wasn't it ? Okay now there are situations in which you will be calling a function existing in global scope from inside of a method in your constructor function. Didn't get what I just said? check out the code below:
I made some small changes in the code for your understanding. In the above code, we have a defined a separate Log( ) service/function which is defined in the global scope. Whenever a user adds a new employee, we want to log this action. Further, we want to check if the number of employees have exceeded our threshold value. In that case, we need to give message that "Employee limit exceeded." .Also notice we initialized the headCount from 10 this time just to create a example out of this situation.
Okay everything looks good, but what happens when we run the above code? Lets check the results...
We can see the headCount exceeding 10 but the condition if(this.headCount > 10) in Log( ) function fails. Why? Ooo yes you are thinking about the right thing. Recall that 'this' in functions defined in global scope refer to the window object. Guess what, Log( ) searched for 'headCount' property in the window object and since it did not find it there, this.headCount returned 'undefined' and 'undefined' > 10 is a falsy condition.
What to do ? Is there a way out? Can we tell the meaning of 'this' to the Log( ) method ? Can we change the meaning of 'this' in a function defined in global scope?
Yes! We can ... by passing 'this' itself when calling the function from our constructor method. See how we are calling the Log( ) method in the code below:
Also, check how we are catching the 'this' passed in the definition of our Log( ) function in the function's local variable called 'emp'. Also see how we have used the 'emp' variable in our if statement and statement within it. 'emp' hold reference to 'this' from where the Log( ) function was called, meaning, 'emp' has all variables and methods of the Employee constructor.
You can use any other variable name in place of 'emp' except the 'this' keyword itself.
[Extra Note: You cannot use the variable name 'this' as a parameter variable in a function. 'this' is reserved keyword and JavaScript will throw errors if you try to do so]
Everything works fine now. Proof? Check it out
'this' when a global function is passed set to a method/event handler
There are several cases in which we have some sort of event handlers on the page. The most famous of them all is click of a button. We usually set click of a button when the DOM has completely loaded, usually on window.onload or within $(document).ready( ) if you are using jQuery. For simplicity, I am not using any DOM manipulation library, so using the simple onload event handler, let's look at an example
Suppose, we have this HTML within our <body>
and within the <head> tag we have this script
SetAction( ) method is called when the DOM is completely loaded (in fact when all resources will also be loaded like images/scripts if any, you may want to read about the difference between onload an document.ready).
Within the SetAction( ) function we are setting handler for button with ID 'btnAddTicket'. If you look closely, here the AddTicket( ) function is used as a method. Why? How can you say that? Because, AddTicket( ) reference is given to a property and if you recall, when a function reference is given to a property/variable, it is called a method.
You may want to guess if this code will run fine since we always see the wrong example first :D This time it's the other way around. Oo yes ! the code works perfectly fine and each time the button is clicked, the counter increments and the text/value/caption of the button indicates how many tickets you have already added. Let's take a look how it looks after I pressed the button for 5 (crazy) times. I am also capturing the console within the screen, have a look at that too.
As I wrote before, "When you call a method in JavaScript, the value of 'this' is set to the object on which the method is called". Same is the case here. AddTicket( ) knows the meaning of 'this' since it called on the button object.
What if I want to do something before I call the handler, may be do some important tasks and then call the function/event handler ( AddTicket( ) ) . Keep in mind that our handler AddTicket( ) is defined in global scope.
Okay let's do what we just said, look at the code below:
This is how we do it in JavaScript. We now have a anonymous function set to the button click, we can do whatever we want in it before calling the AddTicket( ) function.
What happens? Does it work? It looks like the same thing but it isn't !!!! Here AddTicket( ) is no more acting as method. It is now just a function defined in global scope. It is not being set directly as a property, it is being called! That's the difference.
And guess whatttt, we are back from where we started , our friend 'this' in AddTicket( ) now refers back to the global window object, the father of all objects in JavaScript (when running in a browser). Ooo man!!! how to get out of this situation? What to do? How to tell the AddTicket( ) function to still refer to the same 'this' i.e. refer to the button object.
We can do the exact same this as we did before, we can pass the 'this' keyword to the AddTicket( ) function, catch it in as a parameter and use that local variable as we want.
Everything works just fine and we are back on track.
But ,as a Software Engineer(not just a coder), we always have this thing on our mind "Can we do better? Is there a better way ?" The thing we are concerned about is why do we need to pass the 'this' object every time? Subsequently, the global function asks why do I need to catch the scope explicitly of the place from where I was called.
Call( ) and Apply( ) to the rescue!
There are special ways in JavaScript through which you can change the entire meaning of 'this' in any scope. I will not be discussing the difference between call( ) and apply( ) in this article, let's leave it for some other day but by using call/apply we have 3 benefits,
1. We can change the meaning of 'this' in the called function
2. We do not have to explicitly catch it in the called function. (Yes we still explicitly have to throw it from the calling function)
3.The called function i.e. the independent global function again becomes generic and we do not have to change the 'this' keyword with any passed in variable(as we did in our last solution)
Let's check it out:
Everything works just fine once again. You can use apply in exactly similar fashion.
[Extra bits : You may want to read about Call & Apply here.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
]
Another use of 'this' ...a popular one!
I generally try to write anything in the easiest of language possible. This example actually focuses on Function Invocation Pattern in JavaScript. To make it simple, recall the difference when a function is called a function and when it is called a method. I am sharing this final example because you are more likely to find it in any large/small scale JavaSscript application and I don't want you to come back and say "Hey! you missed this use of 'this' in your article. I am not claiming that I have covered every single use of 'this' on earth in this article, but yes the widely used ones.
Consider this example below:
The above example might look a little way off the track but let me try to explain. This is the most easiest example that I was able to come up with.
In the above code, we first define a empty object literal and then we add some method to it separately (This is how we normally do it, create an empty literal and later add whatever we want). When we call the method Add( ), inside it calls another method Helper( ) which is a inner function sort of a thing for Add( ). What I am trying to explain here is the meaning of 'this' in the outer context and within the inner context i.e. within a inner function.
What's the result? Here it is...
Oooo mannn!!! The outer function Add( ) 's 'this' looks fine which is referring to the Employee object literal and showing that it has 1 function that is called Add( ). What happened to the inner function in this case? It is referencing to the global window object. Why? Why did this happen? We need to recall the same story again and again to understand the use of 'this' clearly. The Add( ) function is a method since it is added as a property on the Employee object literal hence 'this' refers to the Employee object literal itself. On the other hand, the inner function Helper( ) is defined independently, not as a property of the Employee Object literal and since Helper( ) is not a method, the 'this' in Helper( ) does not refer Employee object literal but to the global window object.
Is there a word around for this situation, luckily YES!
We first take the reference of 'this' to another variable in the outer function. Traditionally/Historically we name this variable as 'that' but you can name whatever you want. The word 'that' is not a reserved keyword and has no significance. Once we have the reference of 'this' in a new variable, we can then use this new variable to reference to the same meaning of 'this' as it was for the outer function. Please keep in mind that 'this' for inner function is still the same and this is just a popular workaround to over the situation.
So here is the code and console results ...
Points of Interest
Keeping track of 'this' in JavaScript is important. It is very easy to get in a situations where a JavaScript code looks "just fine" when it is not. Majority of the time, it is because of this special 'this' keyword in JavaScript.
I hope I can add more situations for you to understand 'this' in a better way. Leave me a comment here or tweet me about it here >>> @AnasFirdousi