Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why aren't methods of an object created with class bound to it in ES6?

I like ES6 classes but I can't understand why I have to bind methods in the constructor:

constructor() {
    this.someMethod = this.someMethod.bind(this)
}

I need to do this almost for any method.

Is this a real limitation or am I missing something? What is the reason behind this? I know that classes in JS are only syntactic sugar but this could have been part of them.

like image 698
ps-aux Avatar asked Dec 13 '16 17:12

ps-aux


People also ask

Why do class methods need to be bound to a class instance?

This is because whenever inside a class component when we need to pass a function as props to the child component, we have to do one of the following: Bind it inside the constructor function. Bind it inline (which can have some performance issues).

Will ES6 classes bind the instance automatically?

[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.

What would be a reason to use ES6 classes?

ES6 classes are syntactic sugar for the prototypical class system we use today. They make your code more concise and self-documenting, which is reason enough to use them (in my opinion).

Is constructor allowed in ES6 class definition?

But in ES6, we can create the class by using the class keyword. We can include classes in our code either by class expression or by using a class declaration. A class definition can only include constructors and functions.


1 Answers

Quoting Mark Miller's answer to the linked esdiscuss post here:

Several of the early class proposals did so, as they were starting with the semantics of es5 objects-as-closures and classes as compositions-of-instance-traits.

doku.php?do=search&id=traits

The idea was that language support would make this semantics efficient, avoiding the need to eagerly allocate a closure per method per instance.

However, for reasons I understand, these failed to gain traction. Instead, we moves towards sugar for the dominant es5 pattern of encoding classes into prototype inheritance. Initially, we tried to have this purely be sugar, so that people could painlessly refactor code in that dominant pattern into classes.

As we wrestled with the detailed semantics around super and construction, es6 classes deviated from being pure sugar. But this deviation only prevents painless refactoring from es6 classes into the dominant es5 pattern. Practically, it remains painless to refactor from the es5 pattern into es6 classes.

At zenparsing/es-function-bind#17 we realized

we could still have had methods bind on extraction -- accounting for the behavior by decreeing that methods are installed on the prototype as accessors whose getter binds. However, this realization came too late for es6. Since it would have made the refactoring into classes more hazardous -- more of a semantic change -- it is not clear it would have flown even if we had thought of it in time. Instead, under all variations of the decorator designs, one can write such a decorator so that decorated methods are bind-on-extraction, by explicitly creating this accessor property. However(!), if implemented as a user-land decorator, this has much worse performance than objects-as-closures!! Objects-as-closures have higher allocation cost when allocating the object.

jsperf.com/creating-stateful-objects

But are quite efficient at using the object once the object is created:

jsperf.com/strict-where-state

(Note that jsperf is misidentifying Edge 28.14257.1000.0 as Chrome 46.0.2486. This is worth noting because Edge uses the transposed representation for WeakMaps, and so WeakMap-based usage of private state has much less penalty on Edge. Though this is besides the point of this thread.)

To make a decorator for binding-on-extraction efficient, an implementation would need some kind of special case somewhere to avoid the allocation when the method is being immediately invoked, rather than being observably extracted. The only thing TC39 needs to do to enable this is to standardize such a decorator so that implementations can provide it as a builtin that they recognize.

And Kevin Smith's answer:

In general, there is often a tension between making the language "better" (for some subjective value system) and maintaining consistency. I think maintaining consistency was the right call in this case.


That said, the public class fields proposal will allow you to define instance methods as

class Foo {
  someMethod = () => {
    // do stuff
  }
}

(instead of doing the same in the constructor).

like image 102
4 revs, 2 users 98% Avatar answered Sep 28 '22 07:09

4 revs, 2 users 98%