15.6 有关类的常见问题解答
15.6.1 为什么类不能像函数一样调用?
目前禁止用函数的方式调用类。这样做是为将来做准备,为了最终通过类来添加一种处理函数调用的的方式。一种这样做的可能方式是通过一个特殊的方法(例如 [Symbol.functionCall]
)。
15.6.2 究竟如何实例化一个类,传递一组参数?
什么是 Function.prototype.apply()
的类模拟?那就是,如果有一个类 TheClass
和一组数组形式的参数 args
,如何实例化 TheClass
?
一种办法是通过扩展操作符(...):
function instantiate(TheClass, args) {
return new TheClass(...args);
}
另一种方法是使用 Reflect.construct()
:
function instantiate(TheClass, args) {
return Reflect.construct(TheClass, args);
}
15.6.3 如何管理类的私有数据?
两种 ES5 的保持数据私有性的方式对类也有效:
- 1、可以让私有数据存放在类构造器的作用域环境中。我一直不喜欢因此而被迫添加特殊的实例方法。
- 2、可以使用命名约定(例如下划线前缀)来标记私有属性。我喜欢这种方式。这不会对私有属性提供完全的保护,并且略微使命名空间杂乱,但是实现的代码很简单。
在 ECMAScript 6 中,可以使用额外的 WeakMaps
来实现私有数据,这会对方法一中的私有数据提供完全地保护,但是代码更加优雅。下面是如何实现的代码,详细原理在关于 WeakMap 的那一章有讲解:
let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);
_action.set(this, action);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
15.6.4 下一个关于类的内容是什么?
类的设计原则是“最大程度地最小化”。讨论了几种高级的特性,但是最终被放弃了,为了得到一种 TC39 一致认同的设计。
下一个 ECMAScript 版本可以基于这个最小化的设计 - 类将会提供一些基础特性,比如 traits (或者 mixins ),值对象(如果两个不同的对象有相同的内容的话,那么它们是相等的)和常类(生成不可变实例)。