Using Lexical this in JavaScript Class Method with ES6 Arrow Functions

The way JavaScript handles scope is unique. It makes the language so fascinating to learn. It is so different from any other major programming languages. JavaScript has many quirks that make it so fascinating, such as its asynchronous nature, event loops, prototypes, closure and so on. I think this is one of them. It is often misunderstood and misused. But, once you understand how this works, it will take you to the next level.

In this post, we focus on the scoping of this changes with ES6 arrow functions compared to the old way in the context of a class method.

You can see the Past Posts section on the right side of this website (you need to scroll down a bit further) and it has a Show more option (at least, for now. It may be different by the time you are reading this post). That toggler is in fact injected by JavaScript (the real code is actually written in TypeScript, which I will show you at the end).

The class creates a div with the onclick event handler. Now, check out how it is written without an arrow function.

In JavaScript class, this points to the class object. When new is used to create the toggler object, it attaches this to the class object itself. this inside the class method points to the objects within the class. Therefore, you have access to node by this.node. So far, so good.

Take a look at the addEventListener in the render method. If you are using the regular function expression in the callback, this will fall out of scope. This is because this belongs to the call site, which is not the instantiated object itself, but the actual HTML dom (this.node in this case) as this is where event gets triggered. Therefore, if you try to access the clickHandler() with this, JavaScript engine will throw clickHandler not a function TypeError. Hence, we have to attach this to another variable so that the call back function has access to _this.

As mentioned above, this results in not a function TypeError because this falls out of the scope within the callback.

Here comes the ES6 arrow function expression. The syntactical difference is just the surface. The real difference is it creates lexical scope within the function, which was not possible with pre ES6 language specification.

Let’s refactor the render method. You see this within the arrow function can still reference the object within the class. This is cool.

Now all you need to do is instantiate the class and call render method.

As mentioned above, the actual implementation for the archive toggler on this website is done in TypeScript (at the time this post was written). This will probably change in the near future. Here is the code just for fun.

My advice is to embrace arrow functions and use it whenever. Let the transpiler handle the older browser support.

Lastly, arrow functions’s lexical scoping opened up more possibilities to write JavaScript in a new way. Take property initialiser for example. It is an experimental ES6 JavaScript feature that let you write class in a slightly different way by taking advantage of arrow function’s lexical scope. You can check out this post where I use it to refactor  React class component.

Front-End
TypeScript: type aliases to check type equality

This post is to analyse how the type equality check by using type aliases proposed by Matt Pocock in his twitter post. These type aliases allow us to elegantly express type equality checks in unit tests. All we need to do is to pass the output and expected types in …

Front-End
Fixing it.only type error in Jest

If you are getting a type error with it.only in Jest, it could be due to incorrect TypeScript typings or incompatible versions of Jest and TypeScript. To resolve this issue, you can try the following steps: Make sure you have the latest versions of Jest and its TypeScript typings installed …

Front-End
yup conditional validation example

Here’s an example of a Yup validation logic where the first input field is optional but, if filled, it must contain only alphabetic characters, and the second input field is required: import * as Yup from “yup”; const validationSchema = Yup.object().shape({ firstField: Yup.string().matches(/^[A-Za-z]*$/, { message: “First field must contain only …