Differences in Defining ES6 Class Methods
In ES6 there are two common ways to define class methods, but they behave completely different.
The first way is to define them as a standard class function.
class A {
foo() {
console.log('foo from A')
}
}
But you can also define them as an instance specific function:
class A {
foo = () => {
console.log('foo from A')
}
}
The first difference is pretty obvious if you know ES6's fat arrow functions:
It binds the this
variable inside the function call to the this
variable of the scope of where the function was defined.
So in our case, this
will be bound to the current class instance.
We can achieve the same by avoiding arrow functions and use a standard class method in addition to binding it in the constructor:
class A {
constructor() {
this.foo = this.foo.bind(this)
}
foo() {
console.log('foo from A')
}
}
You might now think that the following class definitions have the same behavior:
However, they behave in a completely different way when we use JavaScript's class inheritance.
Class Inheritance yields different results
Let's run the following code:
class A {
constructor() {
this.foo = this.foo.bind(this)
}
foo() {
console.log('foo from A')
}
}
class B extends A {
foo() {
super.foo();
console.log('foo from B')
}
}
new B().foo()
The expected result is logged:
foo from A
foo from B
Let's try the same with fat-arrow functions now:
class A {
foo = () => {
console.log('foo from A')
}
}
class B extends A {
foo = () => {
super.foo();
console.log('foo from B')
}
}
new B().foo()
We get an error:
Cannot read property 'call' of undefined
What's happening here?
Whenever you call super.someFunction
in JavaScript, a lookup for a key someFunction
is done in __proto__
- that's the way JavaScript's class inheritance is implemented.
The reason why we get this error is because foo
is not in __proto__
of the object instance of new B()
.
So, what this tells us is that fat arrow class functions cannot be used from subclasses.
Fat arrow functions can always only be defined through class instance properties. So what our class with transform-class-properties
actually does, is attaching the function first inside the constructor when a concrete class instance is created:
class A {
constructor() {
this.foo = () => {
console.log('foo from A')
}
}
}
Of course, doing it this way, foo
does never exist in __proto__
and makes it unusable in extended classes.
If you need a method to be callable from a derived class (and you want to use the ES6 class
syntax), you need to define that method as a normal class method using shorthand notation:
class A {
constructor() {
this.foo = this.foo.bind(this)
}
foo() {
console.log('foo from A')
}
}
class B extends A {
foo() {
super.foo();
console.log('foo from B')
}
}
new B().foo()
Originally published at https://cmichel.io
Neet. Never thought about using fat arrow function when defining a class. Turns out there is a good reason not to do it :)
I still use fat arrows quite often for React components, to be honest. You just need to be aware that you'll get problems when extending that class.
Oh, I use fat arrow functions all the time! Just not in conjunction with class properties. Inside methods, for callbacks and in promises for example they are great.
This is a good observation that I had never considered, thanks. One of the problems with fat arrows (and even with the
class
keyword in general) is that it effectively covers up the way that Javascript works fundamentally and makes it look like something different.It's super important to understand the basics relating to these features (i.e. Object prototypes and the behaviour of
this
). I strongly recommend to anyone who hasn't already to check out Kyle Simpson's 'You don't know JS`book series which covers both of these topics and many more in careful detail. You're guaranteed to learn a thing or two, and it's free!Yes, I only came across it because my code didn't work and I had to investigate :D Most people just don't really use OOP in JavaScript / React where binding is needed for the event handlers
Congratulations @cmichel! You have completed some achievement on Steemit and have been rewarded with new badge(s) :
Award for the number of upvotes
Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here
If you no longer want to receive notifications, reply to this comment with the word
STOP
Damnn nice coding lesson. I'm still a newby with the coding and this is really hard for me the understand. Gonna read it another 10 times and it might makes sense then! haha
U definetly got another follower mate!
Beyoutiful post you are on fire.
Keep it up god will bless you.