if (read) write

Ramblings from a developer lost in web land.

Date Activity Notes Tags
2023-08-22 Coding init(blog)
2023-08-23 Reading Harmful Class fields gotchas, OOP
tbd Reading ts-pattern In progress lib, pattern
tbd Reading handleEvent In progress api

Class fields can cause harm oh naur

Article by Andrea Giammarchi

Motivation

In my pursuit to better understand JavaScript underthehood™ I've seen it been mentioned that there are obscure differences between methods and arrow functions on Classes e.g. handleClick() {} vs. handleClick: () => {}. I'd like to learn more about the potential pitfalls.

What are the tradeoffs when I use arrow functions? When should I bind this? When should I call(this) What are some alternatives?

Let's get some basics out of the way

Wait..what's a class field again? *GPT-ing* Ok, it's basically a property that can either be private or public; private fields are prefixed by a #. When naming fields there are two that are off-limits: prototype and constructor. Duh.

Point #1

If you create a method using an arrow function, there is no way to override the method if you plan to extend the class. this only exists once super() is called which needs to be called immediately after the constructor is declared. It means any method overrides with the same name will only be scoped locally. NOT the this of the parent class.

When extending a Class, the required super() already has a context this. Creating a method using an arrow function in the extended child instance cannot alter the previously defined method on the parent.

Ok, I give up trying to understand/explain this in my own words. Here's the GPT explanation:

Why This Happens: To understand why this happens, we need to look at how class fields are de-sugared (translated) into traditional JavaScript code that uses prototypes behind the scenes. When you define a class field in a class, such as Counter, the actual method becomes a property of the instance created from that class. In the case of DoubledCounter extending Counter, the method from the parent class is already attached to the instance before the super() call in the subclass's constructor is executed. This means that when you try to override the method in the subclass, you're actually creating a new method that gets assigned after the initial parent method is already attached.

I was still a bit unclear as to why redefining a method doesn't override the parent's method regardless of definition order. Does that mean subclass methods with matching parent class methods can never be overridden?

Point #2

There are a few ways to get the expected behavior:

  1. Stick to the old way handler.bind(this)
  2. Cut out all the sugar and define your method on the prototype
  3. Via accessor get
  4. Double arrow functions?? This is getting too complicated
  5. Last but not least: handleEvent()* This will be the focus of my next post as I'll hopefully be using it extensively in future projects

Cool bits

I learned what a class field is and better yet I learned it can be computed.[`${taco}`] = 'suadero'

I don't think I answered my original questions that motivated me to read this article in the first place. Though, I'm glad I decided to start writing again.