主题
扩展内建类
扩展内建类指的是:让自定义类继承 Array、Error、Map 这类 JavaScript 已有的内建构造器。
什么场景会用到
更常见的情况包括:
- 想给数组补充一组领域方法
- 想定义自定义错误类型
- 想在保留原有行为的基础上增加额外能力
基本写法
js
class PowerArray extends Array {
isEmpty() {
return this.length === 0
}
}
const arr = new PowerArray(1, 2, 3)
console.log(arr.isEmpty()) // false
console.log(arr instanceof Array) // true
console.log(arr instanceof PowerArray) // true这里 PowerArray 既保留了数组行为,又增加了自己的方法。
扩展 Array
这是最常见的例子:
js
class PowerArray extends Array {
last() {
return this[this.length - 1]
}
}
const arr = new PowerArray(1, 2, 3)
console.log(arr.last()) // 3这样得到的实例仍然可以继续使用 push、map、filter 等数组方法。
内建方法返回的结果类型
扩展内建类时,一个容易忽略的问题是:某些内建方法返回的新对象,默认也会沿用子类类型。
js
class PowerArray extends Array {}
const arr = new PowerArray(1, 2, 3)
const filtered = arr.filter((item) => item > 1)
console.log(filtered instanceof PowerArray) // true这通常是合理的,但有时并不是想要的结果。
Symbol.species
如果希望这类派生操作返回原始内建类型,而不是子类,可以使用 Symbol.species:
js
class PowerArray extends Array {
static get [Symbol.species]() {
return Array
}
}
const arr = new PowerArray(1, 2, 3)
const filtered = arr.filter((item) => item > 1)
console.log(filtered instanceof PowerArray) // false
console.log(filtered instanceof Array) // true可以把它理解成“派生结果默认应该是什么构造器”。
扩展 Error
另一个很常见的场景是自定义错误类型:
js
class ValidationError extends Error {
constructor(message) {
super(message)
this.name = 'ValidationError'
}
}
throw new ValidationError('invalid email')这样可以:
- 保留原有错误对象结构
- 用
instanceof区分错误类型 - 在业务里按类型处理错误
扩展内建类不是“随便加方法”
虽然语法允许继承内建类,但是否真的适合,要看类型本身和团队约定。
例如:
- 给
Array增加少量强语义方法,通常还算自然 - 给
Map、Set做强领域封装,也可能合理 - 把大量业务逻辑塞进
Array子类,往往会让边界变糊
和直接改原型不是一回事
扩展内建类:
js
class PowerArray extends Array {}修改全局原型:
js
Array.prototype.last = function () {
return this[this.length - 1]
}两者差别很大。前者只影响自己的子类实例,后者会污染所有数组实例。
一般更应避免直接改内建原型,尤其是在应用代码和共享库里。
什么时候适合用
更适合:
- 需要保留内建类型行为
- 只增加少量明确能力
- 需要
instanceof和类型层级
如果只是想复用几个辅助方法,工具函数通常更直接。
使用建议
- 只有在“它本质上仍然是那个内建类型”时,再考虑继承内建类。
- 自定义错误类型是扩展内建类里最实用的一类场景。
- 遇到返回结果类型不符合预期时,优先想到
Symbol.species。 - 不要用“继承内建类”替代普通工具函数或组合设计。
