Array、Map 等内置类也是可扩展的。
例如,此处 PowerArray 从原生 Array 继承
// add one more method to it (can do more)
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
let filteredArr = arr.filter(item => item >= 10);
alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
请注意一个非常有趣的事情。filter、map 等内置方法会返回准确继承类型 PowerArray 的新对象。它们的内部实现为此使用了对象的 constructor 属性。
在上面的示例中,
arr.constructor === PowerArray
当调用 arr.filter() 时,它会在内部使用准确的 arr.constructor 而不是基本的 Array 来创建新的结果数组。这实际上非常酷,因为我们可以继续在结果上使用 PowerArray 方法。
更重要的是,我们可以自定义该行为。
我们可以向类添加一个特殊的静态 getter Symbol.species。如果它存在,它应该返回 JavaScript 将在内部用于在 map、filter 等中创建新实体的构造函数。
如果我们希望像 map 或 filter 这样的内置方法返回常规数组,我们可以在 Symbol.species 中返回 Array,如下所示
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
// built-in methods will use this as the constructor
static get [Symbol.species]() {
return Array;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
// filter creates new array using arr.constructor[Symbol.species] as constructor
let filteredArr = arr.filter(item => item >= 10);
// filteredArr is not PowerArray, but Array
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
如你所见,现在 .filter 返回 Array。因此,扩展功能不会进一步传递。
其他集合,如 Map 和 Set,工作方式类似。它们也使用 Symbol.species。
内置中没有静态继承
内置对象有自己的静态方法,例如 Object.keys、Array.isArray 等。
正如我们已经知道的,原生类相互扩展。例如,Array 扩展 Object。
通常,当一个类扩展另一个类时,静态方法和非静态方法都会被继承。这在文章 静态属性和方法 中得到了详尽的解释。
但内置类是一个例外。它们不会相互继承静态方法。
例如,Array 和 Date 都继承自 Object,因此它们的实例具有来自 Object.prototype 的方法。但 Array.[[Prototype]] 不引用 Object,因此没有 Array.keys()(或 Date.keys())静态方法。
以下是 Date 和 Object 的图片结构
如你所见,Date 和 Object 之间没有链接。它们是独立的,只有 Date.prototype 继承自 Object.prototype。
这是内置对象与我们使用 extends 获得的继承之间的重要区别。
评论
<code>标签,对于多行代码 – 将它们包装在<pre>标签中,对于超过 10 行的代码 – 使用沙箱(plnkr、jsbin、codepen…)