为什么在 ES6 中创建的对象的方法没有绑定到它的类? [英] Why aren't methods of an object created with class bound to it in ES6?

查看:9
本文介绍了为什么在 ES6 中创建的对象的方法没有绑定到它的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢 ES6 类,但我不明白为什么我必须在构造函数中绑定方法:

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

我几乎对任何方法都需要这样做.

这是一个真正的限制还是我遗漏了什么?这背后的原因是什么?我知道 JS 中的类只是语法糖,但这可能是其中的一部分.

解决方案

引用 Mark Miller 对 链接的讨论帖在这里:

<块引用>

一些早期的类提案是这样做的,因为它们从 es5 对象作为闭包和类作为实例特征组合的语义开始.

doku.php?do=search&id=traits

<块引用>

这个想法是语言支持将使这种语义有效,避免急切地为每个方法每个实例分配一个闭包的需要.

<块引用>

然而,由于我理解的原因,这些未能获得关注.相反,我们将主要的 es5 模式转向将类编码为原型继承的糖.最初,我们试图让这纯粹是糖,以便人们可以轻松地将这种主导模式中的代码重构为类.

<块引用>

当我们与围绕 super 和构造的详细语义搏斗时,es6 类偏离了纯糖.但是这种偏差只会阻止从 es6 类到主导的 es5 模式的无痛重构.实际上,从 es5 模式重构为 es6 类仍然很容易.

<块引用>

zenparsing/es-function-bind#17 我们实现了

<块引用>

我们仍然可以在提取时绑定方法——通过下令将方法安装在原型上作为其 getter 绑定的访问器来解释行为.然而,对于 es6 来说,这种认识来得太晚了.由于它会使重构为类变得更加危险——更多的是语义变化——即使我们及时想到它,也不清楚它是否会成功.相反,在装饰器设计的所有变体下,可以编写这样的装饰器,以便通过显式创建此访问器属性来将装饰方法绑定到提取.然而(!),如果实现为用户空间装饰器,这比对象作为闭包的性能要差得多!!对象即闭包在分配对象时具有更高的分配成本.

<块引用>

jsperf.com/creating-stateful-objects

<块引用>

但是在创建对象后使用对象非常有效:

<块引用>

jsperf.com/strict-where-state

<块引用>

(请注意,jsperf 将 Edge 28.14257.1000.0 错误识别为 Chrome 46.0.2486.这一点值得注意,因为 Edge 使用 Wea​​kMap 的转置表示,因此基于 WeakMap 的私有状态使用对 Edge 的惩罚要小得多.虽然这不是这个线程的重点.)

<块引用>

为了使提取时绑定的装饰器高效,实现需要在某处某种特殊情况,以避免在立即调用方法时进行分配,而不是被可观察地提取.要实现这一点,TC39 唯一需要做的就是标准化这样的装饰器,以便实现可以将其作为它们识别的内置函数提供.

凯文史密斯的回答:

<块引用>

一般来说,在使语言更好"和更好"之间常常存在紧张关系.(对于某些主观价值体系)并保持一致性.我认为在这种情况下保持一致性是正确的要求.


也就是说,公共类字段 proposal 将允许您将实例方法定义为

class Foo {someMethod = () =>{//做东西}}

(而不是在 constructor 中做同样的事情).

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.

解决方案

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).

这篇关于为什么在 ES6 中创建的对象的方法没有绑定到它的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆