【JS】扩展内建类 - Symbol.species
Symbol.species 是个函数值属性,其被构造函数用以创建派生对象,
Symbol.species访问器属性允许子类覆盖对象的默认构造函数。
JS内建类可以被扩展
class MyArray extends Array {
isEmpty(){
return this.length === 0
}
}
const arr = new MyArray(1,2,3,4,5)
console.log(arr.isEmpty()); // false
const newArr = arr.filter(item => item > 3)
console.log(newArr.length,newArr.isEmpty()); 2,false
我们可以发现当 arr.filter()
被调用时,它的内部使用的是 arr.constructor
来创建新的结果数组,而不是使用原生的 Array
。因此我们可以在结果数组上继续使用 MyArray
的方法。
我们可以给这个类添加一个特殊的静态 getter Symbol.species
。如果存在,则应返回 JavaScript 在内部用来在 map
和 filter
等方法中创建新实体的 constructor
。
class MyArray extends Array {
isEmpty(){
return this.length === 0
}
static get [Symbol.species](){
return Array
}
}
const arr = new MyArray(1,2,3,4,5)
console.log(arr.isEmpty()); // false
const newArr = arr.filter(item => item > 3)
console.log(newArr.length,newArr.isEmpty()); // newArr.isEmpty is not a function
这时,arr.filter()
创建的数组对象是使用Array
创建的,所以不能使用MyArray.prototype
上的方法。
内建类的静态方法不能被继承
内建对象有它们自己的静态方法,例如 Object.keys
,Array.isArray
等。
通常,当一个类扩展另一个类时,静态方法和非静态方法都会被继承。但内建类却是一个例外。它们相互间不继承静态方法。
下图中,Array
和 Date
都继承自 Object
,所以它们的实例都有来自 Object.prototype
的方法。但 Array.[[Prototype]]
并不指向 Object
,所以它们没有例如 Array.keys()
(或 Date.keys()
)这些静态方法。
与普通类的继承相比,内建类之间的extends只创建了一个[[Prototype]]引用,Child.[[prototype]] = Parent.prototype