In a previous post, I was explaining how a that = this
assignment was required to preserve the value of the this
variable in certain scenarios. This post will focus on how to resolve them using arrow functions.
Before continuing, I strongly recommend that you read my previous post to understand why ‘that = this assignments’ were made back then and also to understand how a this
variable gets it’s value.
In the previous post, I made an example using object literal declaration which made it impossible to preserve the value of this
using arrow functions. So, we will discuss a different example that uses a that = this
assignment to preserve the value of the this
variable and later we will see how it can be replaced with arrow functions.
Consider the following example:
var name = "Global Person"; function Person() { this.name = ""; this.printName = function() { console.log(this.name); } } var perA = new Person(); perA.name = "Person A"; perA.printName() //prints Person A
In the above scenario, the new
operator is used on a function when it is invoked. This is a special type of function invocation called constructor function invocation. In this type of function invocation, a new empty object is created, (let’s name it newObj
) and the function is invoked on that object, like say, newObj.Person()
in this case. This means, the value of this
is set to newObj
for the invocation. Once, the invocation is done the newObj
is returned and assigned to the perA
variable.
We then set the value of the name
attribute of that particular object instance, i.e, perA
and invoke the printName
method on that object. Everything works as expected. “Person A” is printed.
Now, lets change things up.
var printNameReference = perA.printName; printNameReference(); //prints Global Person
Here you can see that the type of function invocation is a stand alone function invocation rather than a invocation using the dot operator. This means that the value of this
is set to the global object and hence “Global Person” is printed.
The takeaway here is that, though the function was defined on the object, this does not necessarily mean that the value of this
is always set to that particular object. It all depends on the way the function is invoked.
Scenarios like this generally happen when you dynamically add event listeners to DOM elements, say,
myButton.addEventListener('click', obj.myFunction);
In the above statement, if myFunction
depends on the value of this
in it’s implementation, then you will end up getting undesired results.
So how do we fix this?
There are a couple of ways around it, one simple way used back then was to save the value of this
in a local variable so that we can use it later when we need it.
var name = "Global Person"; function Person() { var self = this; this.name = ""; this.printName = function() { console.log(self.name); } } var perA = new Person(); perA.name = "Person A"; perA.printName() //prints Person A var printNameReference = perA.printName; printNameReference(); //prints "Person A"
In the above code, even though printNameReference
is a standalone invocation, the printName
function actually makes use of the self
variable, rather than depending on the call site to get the correct value of this
and hence “Person A” is printed.
What we have seen so far was before the advent of arrow functions. Arrow functions make the job much simpler as the value of the this
variable for an arrow function is bound to the enclosing scope at creation time and cannot be changed. The new
operator, bind
, call
, and apply
functions have no effect on the this
value of a arrow function.
So say we modify the above code as follows
var name = "Global Person"; function Person() { this.name = ""; this.printName = () => { console.log(this.name); } } var perA = new Person(); perA.name = "Person A"; perA.printName() //prints Person A var printNameReference = perA.printName; printNameReference(); //prints "Person A"
Since the printName
function was defined as an arrow function rather than the traditional anonymous function, and since it is defined within the lexical scope of the function Person
, the value of this
is set to the surrounding lexical scope.
As mentioned earlier, the value of this
for an arrow function cannot be changed at run time.
As a result even though printNameReference()
is a standalone function invocation, we still end up with the correct this
value, as it cannot be overridden by the invocation.
Thus arrow functions enable us to preserve the value of the this
variable and alleviate the need to make local variable assignments like ‘that = this’ or ‘self = this’. See you in the next one guys..Peace.. 🙂
Pingback: Preserving the value of ‘this’ using arrow functions | Ace Infoway
Pingback: Replacing ‘that = this’ assignments in JavaScript with Arrow Functions – Full-Stack Feed
Pingback: Replacing ‘that = this’ assignments in Javascript with Arrow Functions | ExtendTree