Page 248 - 你不知道的JavaScript(下卷)
P. 248
要在一个函数上设定 @@hasInstance,必须使用 Object.defineProperty(..),
因为 Function.prototype 上默认的那一个是 writable: false(不可写的)。
参见本系列《你不知道的 JavaScript(上卷)》第二部分获取更多信息。
7.3.3 Symbol.species
在 3.4 节中,我们介绍了符号 @@species,这个符号控制要生成新实例时,类的内置方法使
用哪一个构造器。
最常见的例子是,在创建 Array 的子类并想要定义继承的方法(比如 slice(..))时使用
哪一个构造器(是 Array(..) 还是自定义的子类)。默认情况下,调用 Array 子类实例上的
slice(..) 会创建这个子类的新实例,坦白说这很可能就是你想要的。
但是,你可以通过覆盖一个类的默认 @@species 定义来进行元编程:
class Cool {
// 把@@species推迟到子类
static get [Symbol.species]() { return this; }
again() {
return new this.constructor[Symbol.species]();
}
}
class Fun extends Cool {}
class Awesome extends Cool {
// 强制指定@@species为父构造器
static get [Symbol.species]() { return Cool; }
}
var a = new Fun(),
b = new Awesome(),
c = a.again(),
d = b.again();
c instanceof Fun; // true
d instanceof Awesome; // false
d instanceof Cool; // true
就像前面代码中 Cool 的定义那样,内置原生构造器上 Symbol.species 的默认行为是
return this。在用户类上没有默认值,但是就像展示的那样,这个行为特性很容易模拟。
如果需要定义生成新实例的方法,使用 new this.constructor[Symbol.species](..) 模式
元编程,而不要硬编码 new this.constructor(..) 或 new XYZ(..)。然后继承类就能够自定
义 Symbol.species 来控制由哪个构造器产生这些实例。
元编程 | 225
图灵社区会员 avilang(1985945885@qq.com) 专享 尊重版权