this and Arrow Functions:
Another significant advantage it offers is the fact that it does not bind its own
this. In other words, the context inside arrow functions is lexically or statically defined.
What do we mean by that?
Unlike other functions, the value of
this inside arrow functions is not dependent on how they are invoked or how they are defined.It depends only on its enclosing context.
Let us try to understand with an example:
[object Object] undefined is undefined years old
The reason that we get undefined outputs instead of the proper info as output happens because the
function() defined as the callback for setTimeout has a normal function invocation and as we know, this means that its context is set to the global context or in other words the value of
this is set to the window object.
This happens because every regular, non-arrow function defines its own
this or context depending on their invocation.The context of the enclosing objects/function does not affect this tendency to automatically define their own context.
How do we solve this?
One obvious solution that comes to mind is, what if the function did not define its own context?What if it inherited the context from the
info(), because that would mean this function() gets the
this as was defined in
Well, that is exactly what arrow functions do.They retain the value of
this from their enclosing
That is, in the above example, if the function defined as callback for
setTimeout() were an arrow function it would inherit the value of
this from it’s enclosing context –
[object Object] John is 21 years old
Thus, regardless of whether the arrow function was called using function invocation or method invocation, it retains the ]value of
this from its enclosing context.In other words, an arrow function’s
this value is the same as it was immediately outside it.
If used outside any enclosing function, an arrow function inherits the global context, thereby setting the value of
this to the global object.
this in separated methods:
When a method from any object is separated from it, or stored in a variable, eg :
let separated = People.info, it loses the reference to its calling object.
Notice the lack of opening and closing parentheses after
info. This indicates that we are not calling the method immediately.
For instance :
[object Object] John is 21 years old [object Window] undefined is undefined years old
Once we separate the
info() from the
person1 object by storing it in
separated, we lose all references to the
We can no longer access the parent object by using
this inside the separated method because the context of the separated method gets reset to the global context.
Thus, when we call
separated() we see that
this is now set to the global window object.
How do we solve this?
One way is to
bind the value of an object with the method when storing the method in
separated. This ensures that all references to
this refers to this bound object even in the separated method.
This can be done using
bind() like so:
[object Object] John is 21 years old [object Object] John is 21 years old
Note: We could have used any object to
bind() to the method
info(), instead of, code.person1, and the outputs would have changed accordingly.It is not mandatory to bind a method to it’s parent object.
If you have come this far you would have noticed that we mentioned
bind() a couple of times.
Let us now study what
bind(), call() and apply() really are.
bind, call and apply
bind(), call() and apply() are all used to modify the context of a function. All three of these help explicitly specify what the value of
this should be inside a function.
But, there are certain differences in how each of them work. Let us study these differences.
bind() allows us to explicitly define what value
this will have inside a function by binding an object to that function.
The bound object serves as the context(
this value) for the function that it was bound to.
To use it, we need primarily two things – An object to bind to a function and a function that this object is to be bound to.
The general syntax for bind is :
boundfunction = someFunction.bind(someObject, additionalParams);
The first argument used inside the bind() directive serves as the
this value and the arguments that follow it are optional and serve as the arguments for the bound function.
Orange is orange Banana is Yellow
Notice that we call displayInfo() on fruit1 using method invocation :
fruit1.displayInfo and therefore might expect it to have the context of
fruit1. However this does not seem to be the case as “Banana is Yellow” gets logged instead of “Orange is orange”.
This happens because we explicitly bind the value of
this inside displayInfo() using the
bind() command to
As we can see, binding an object explicitly to a function overrides its normal context rules and forcefully sets all
this values to the bound object inside it.
Often, when passing functions around, it loses its context.For instance:
[object Window] undefined
To prevent resetting of context inside the function passed as callback, we explicitly bind the value of
this to be the same as it was inside
passAround(), i.e:to the
binding object :
[object Object] John
call() and apply()
call() and apply() perform a task similar to bind by explicitly specifying what value
this should store inside a function.
However, one major difference between them and
bind() is that
call() and apply() immediately calls the function, as opposed to simply preparing a copy of the function with a bound
this value for future use.
function.call(thisValue, arg1, arg2, ...)
function.apply(thisValue, [ arg1, arg2, ...])
The first argument in both cases is the value of
this that we wish for the called function to have.
Essentially, the only difference between these two methods is the fact that in
apply , the second argument is an array object of arguments while in
call, all arguments are sent in a comma separated format.
[object Object] Banana is yummy [object Object] Orange is sour
apply() are methods that are available on the prototype of the default Function object.
this with event listeners
Inside functions used as callbacks for event listeners,
this holds the value of the element that fired the event.
If the callback function used here is an arrow function and our event listener is nested inside another method,
this would refer to the context of the outer nesting method, and we can no longer access the element that the event listener is added to using
this, like we had in the previous code example.
Fortunately, this can be easily resolved by using the
currentTarget method on the element like so:
[object HTMLButtonElement] Correctly identified!
As we can see, using the
currentTarget allows us to access the element that the event listener is added on while
this allows us to access the context of the enclosing function – i.e:
this allows us to successfully call the displayInfo() method.