切换主题
扩展内置类
继承内置类
1. 扩展 Array
javascript
class MyArray extends Array {
// 添加新方法
first() {
return this[0];
}
last() {
return this[this.length - 1];
}
// 添加新的 static 方法
static fromRange(start, end) {
return new MyArray(...Array(end - start + 1).keys()).map(x => x + start);
}
}
const arr = new MyArray(1, 2, 3, 4, 5);
console.log(arr.first()); // 1
console.log(arr.last()); // 5
console.log(arr instanceof Array); // true
console.log(arr instanceof MyArray); // true
// 使用静态方法
const range = MyArray.fromRange(5, 10);
console.log(range); // MyArray(6) [5, 6, 7, 8, 9, 10]
2. 扩展 Map
javascript
class ExtendedMap extends Map {
// 返回键的数组
keys() {
return [...super.keys()];
}
// 返回值的数组
values() {
return [...super.values()];
}
// 添加多个键值对
setMultiple(entries) {
for (const [key, value] of entries) {
this.set(key, value);
}
return this;
}
// 获取第一个键值对
firstEntry() {
const iterator = super.entries();
return iterator.next().value;
}
}
const map = new ExtendedMap();
map.set('a', 1).set('b', 2);
console.log(map.keys()); // ['a', 'b']
console.log(map.firstEntry()); // ['a', 1]
map.setMultiple([['c', 3], ['d', 4]]);
console.log(map.size); // 4
3. 扩展 Promise
javascript
class TimedPromise extends Promise {
// 记录执行时间
static async withTimer(executor) {
const start = Date.now();
try {
const result = await new Promise(executor);
const end = Date.now();
return {
result,
time: end - start
};
} catch (error) {
const end = Date.now();
throw {
error,
time: end - start
};
}
}
// 创建一个超时 Promise
static timeout(ms, value) {
return new TimedPromise((resolve) => {
setTimeout(() => resolve(value), ms);
});
}
}
// 使用扩展的 Promise
async function test() {
const result = await TimedPromise.withTimer(async (resolve) => {
await new Promise(r => setTimeout(r, 1000));
resolve("完成");
});
console.log(`操作耗时: ${result.time}ms, 结果: ${result.result}`);
const timeoutResult = await TimedPromise.timeout(500, "超时完成");
console.log(timeoutResult);
}
test();
继承内置类的特殊行为
1. 返回值重写
javascript
class MyArray extends Array {
// 重写 Array 方法
static get [Symbol.species]() {
return Array;
}
// 自定义 filter 方法
customFilter(callback) {
console.log('使用自定义 filter');
return this.filter(callback);
}
}
const myArray = new MyArray(1, 2, 3, 4, 5);
const filtered = myArray.filter(x => x > 2);
console.log(filtered instanceof Array); // true
console.log(filtered instanceof MyArray); // false (因为我们重写了 Symbol.species)
const customFiltered = myArray.customFilter(x => x > 2);
console.log(customFiltered instanceof Array); // true
console.log(customFiltered instanceof MyArray); // false
2. 内置方法调用子类构造函数
javascript
class MyArray extends Array {
constructor(...args) {
console.log('MyArray constructor called');
super(...args);
}
}
// 直接调用构造函数
const arr1 = new MyArray(1, 2, 3);
console.log(arr1); // MyArray(3) [1, 2, 3]
// map 方法创建新实例时也会调用构造函数
const arr2 = arr1.map(x => x * 2);
console.log(arr2); // MyArray(3) [2, 4, 6]
// concat 方法也会调用构造函数
const arr3 = arr1.concat([4, 5]);
console.log(arr3); // MyArray(5) [1, 2, 3, 4, 5]
最佳实践与注意事项
1. 性能考虑
javascript
// 不要盲目扩展内置类
class HeavyArray extends Array {
constructor(...args) {
super(...args);
this.metadata = {
createdAt: new Date(),
id: Math.random().toString(36)
};
}
// 每次调用都会生成大量数据的方法可能导致性能问题
analyze() {
return {
sum: this.reduce((a, b) => a + b, 0),
average: this.reduce((a, b) => a + b, 0) / this.length,
min: Math.min(...this),
max: Math.max(...this),
// ... 其他计算
};
}
}
// 对于大型数组,这种扩展可能导致性能问题
2. 最佳实践
- 谨慎扩展内置类,考虑组合而不是继承
- 了解 Symbol.species 的作用
- 避免覆盖原始类的核心功能
- 为扩展类添加有意义的方法和属性
- 考虑扩展对性能的影响
- 测试所有继承的方法
- 记录继承类的行为差异
- 考虑使用工具函数代替扩展类