The Problem
Suppose you had the following class:
class Dog {
numOfLegs = 4;
getLegCount = function() {
console.log(this.numOfLegs);
}
}
Now let's say you had an instance of a Dog:
const dog = new Dog();
We can call the getLegCount
method like so:
dog.getLegCount();
The output would be "4", as expected. But what if we destructured our Dog object:
const { getLegCount } = new Dog();
Let's update the call to the method accordingly:
getLegCount();
And while we might expect the output to be the same, we instead get
Uncaught TypeError: this is undefined
Why would this be the case? When destructuring a method on a class, the method's this
context is no longer bound, leading to the error.
The Solution
How do we keep the this
context? There are two ways of doing so. The first option is to explicitly set the binding of the this
context to the method in the class constructor:
class Dog {
constructor() {
this.getLegCount = this.getLegCount.bind(this);
}
numOfLegs = 4;
getLegCount = function() {
console.log(this.numOfLegs);
}
}
This will resolve the issue and output 4
, as expected.
The second option is to use an arrow function to define the getLegCount
method:
class Dog {
numOfLegs = 4;
getLegCount = () => {
console.log(this.numOfLegs);
}
}
This too resolves the issue of the this
context and does so without having to explicitly bind the context to the method. Though often times misunderstood to be completely interchangeable, the arrow function differs from the traditional function expression in that it does not have it's own binding to this
and therefore will close over the class's this
context.
Note that this only works correctly over classes and not traditional objects due the fact of the class having its own this
context whereas an object's this
context would be the global this
.
For example, having the following object:
const dog = {
numOfLegs: 4,
getLegCount: () => {
console.log(this.numOfLegs);
}
};
In calling the destructured method:
const { getLegCount } = dog;
You would see the output as:
undefined
Conclusion
Arrow functions were introduced in ES6 or ECMAScript 2015 so as long as you don't need to support older legacy systems or are using a tool to ensure backwards compatibility (such as Babel or TypeScript), arrow functions are a fine approach. Whichever approach you take, you now have a deeper insight into the differences between () => {}
and function() {}
.
Top comments (0)