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?
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...
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...
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...
'this' when used inside an Object Literal
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.
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 !]
'this' when used in a Constructor Function
How to make use of constructor functions to create objects?
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:
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.
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.
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:
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.
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!
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.
Another use of 'this' ...a popular one!
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
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