DEV Community

Richard Torres
Richard Torres

Posted on • Edited on

How to Destructure Class Methods

The Problem

Suppose you had the following class:

class Dog {
    numOfLegs = 4;

    getLegCount = function() {
        console.log(this.numOfLegs);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now let's say you had an instance of a Dog:

const dog = new Dog();
Enter fullscreen mode Exit fullscreen mode

We can call the getLegCount method like so:

dog.getLegCount();
Enter fullscreen mode Exit fullscreen mode

The output would be "4", as expected. But what if we destructured our Dog object:

const { getLegCount } = new Dog();
Enter fullscreen mode Exit fullscreen mode

Let's update the call to the method accordingly:

getLegCount();
Enter fullscreen mode Exit fullscreen mode

And while we might expect the output to be the same, we instead get

Uncaught TypeError: this is undefined
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
};
Enter fullscreen mode Exit fullscreen mode

In calling the destructured method:

const { getLegCount } = dog;
Enter fullscreen mode Exit fullscreen mode

You would see the output as:

undefined
Enter fullscreen mode Exit fullscreen mode

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)