Join the DZone community and get the full member experience.Join For Free
Let's get them right once and for all.
If I were to talk about this in a literal sense, it simply means — this very thing in front of me. “This jacket is cool,” claimed my sister holding that jacket in her hand. I replied back saying, “No, this one’s better!” I was referring to the jacket near to me and she was referring to the one near her and hence the use of this in respective statements.
Value of this depends on:
- The Execution Context
Execution Context is the environment in which the code runs. For example, the local variables of a function would be accessible in that function only and not outside of it. This is called Functional Level Scoping or Local Execution Context. Variables declared in the global scope (outside of any function) would be accessible in all the underlying functions. This is called the Global Execution Context.
Let’s consider this example to understand the difference between the two of them:
The value of
this in the Global Execution Context by default is the
The value of
this in any Local Context depends on the way the function is called.
I. Calling a function in a Global context would have its
this value as
III. Calling a function that is inside an object.
add is one of the properties on object,
obj. When we call add with reference to
obj.add(), it gets called in the context of
b have definite value in the context of
obj, so that result of
obj.add() is defined.
cacheAdd variable stores the reference of the
add function. If we execute this function at a later stage, it will run in the context from where it is called. In our example, we’re calling
cacheAdd in the global context, so it will have a global object as the
this reference. Since
b are not defined in the global context, we’re getting the value of
To prove this point, lets define
b in the global context.
obj.add() evaluates to 3 as the value of
b defined in
obj is 1 and 2, respectively. When we run
add after caching it in a variable and then executing it in the global context, it evaluates to 7 as the value of
b in the global context are 3 and 4, respectively. So, a function that uses
this may give a different result depending on the context in which it is executed.
Let's try another interesting example:
In this case, the
add function returns another function and the value of
a+b is executed in this inner function.
obj.add() will return a function that has one console statement. So, we have to execute this returned function in order to get the sum of
b. But this returned function (returned on executing
obj.add()) will run in the global context and hence the value of
a+b evaluates to 7 (the value of
b in the global context is 3 and 4, respectively).
add function prints the value of
b after a timeout of 500ms.
setTimeout runs in the global context.
setTimeout run in the global context? (I’ll explain about it in detail in my next post.)
this takes the reference of the immediate object calling the function.
childObj as one of the properties and add function is defined on
childObj. When we call
add function takes
this the reference of
childObj and variables
b are not accessible from the local context of
childObj Hence the value of
b is undefined.
Linking to the Prototype Chain
If we instantiate
parentObj to create
childObj, its properties would be accessible in the
add function gets called in the context of
childObj, it first tries to look for values of
c in the context of
childObj and if any of these values is undefined, it looks up to its parent context, which in this case is
In this case, also, properties of parent are available in the context of child. As we can see in the trailing console statement, the constructor of the child is defined as the Parent. So, it first checks for values in the context it is called and then look up to its prototype chain.
This Ain’t Rocket Science!
By default, the code runs in the global context, i.e. it has access to the variables defined in the context of the
window object. In each of the above cases, we’re just restricting the context to the
obj object. All the operations related to this will be carried out in the exact same way as they would have if the context was
window. Even with the global context, if any of the values are not defined, it looks up to the prototype chain.
As we can see, the
toString function is defined in the
__proto__ property of
obj, which means it is defined on the prototype of
obj is created by applying the
new operator to
toString is not defined in the context of
obj, it looks up to its prototype chain.
Let’s solve an interesting issue here.
My sister stubbornly refuses to share the candy with me and to support her claim, she says, she is the owner of this candy.
This is her candy:
So, somehow I have to modify the
this reference so that the function
Call, Apply, and Bind. Here I Go!
With these three beautiful functions, you can modify the value of the
this reference. In the above example,
candy.whosCandyIsThis.call(myCandy) modifies the
this reference of the
whosCandyIsThis function to
call All About?
call explicitly passes the
this reference to a function. In this case, it tells the
whosCandyisThis function to use
The first argument of
call is the
this reference and if we have to pass in any additional parameters, you can do something like this:
Let’s take one more example.
Here, we’re passing the
this reference explicitly with the
displayMenu function defined in the hotel object to display the menu accordingly (isn’t this cool?).
But what if I want to display the menu based on the user’s location. For that, we’ll pass an additional parameter,
location, to the
displayMenu function. Let’s modify the above code to fit in our requirements.
The first parameter of call is the
this reference and then you can pass in any number of arguments that you want. The
displayMenu function now shows the list of menu items as per the
Apply operates in the same way as
call, the only difference being the way in which we pass arguments.
Apply takes in the first parameter as the
this reference just like we did with
call but other parameters are to be passed as an array.
Another function that can modify the
this reference is
apply, that return the result of the function,
bind returns a function. And this returned function can then be called at any later stage. It will run in the context of an explicitly passed bounded argument.
hotel.displayMenu.bind(ccd) returns a function that has the
this reference of
ccd. When we run
boundFunction, it runs in the context of
ccd and hence prints Espresso for location A.
I was trying an experiment. If I bind an already bound function to some other reference, would that function run in the context of the later binding? If this is true, I can do this endlessly and keep changing this reference with all the power I have! But, this is not true. You can only bind a function once. In the above example, I’ve tried to bind the bounded function again with
pizzaCentre but when I execute this function, it prints the previous result which means its reference still points to the first binding (
This is how it works. Plain and simple.
Why are we even talking about arrow functions in this article? What’s so special about them?
In an arrow function, the value of
this is that of its enclosing lexical context Lexical Context is block level scoping. It does not change with
Arrow functions maintain the binding of
this and of its enclosing lexical context.
Crap! This arrow took away my candy.
As you can see,
whosCandyIsThis is defined as an arrow function. So it will maintain the binding of its Lexical Context. On instantiating Candy,
niks sets the owner and flavor for her candy. Tje
whosCandyIsThis function gets bound to the
So, when I try to call it explicitly by passing the
this reference using
bind, it doesn’t work. The bindings of the
niks.whosCandyIsThis function cannot be changed, whatsoever!
You might like my previous articles on Service Workers:
Published at DZone with permission of Ankita Masand. See the original article here.
Opinions expressed by DZone contributors are their own.