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