Mik*_*ike 1 class-extensions typescript
我想向Array类添加一些函数(我宁愿不要将它们作为类外部的函数使用,因为理想情况.下,在对象后面键入时可以发现它们)。这是我到目前为止的内容:
export class List<T> extends Array<T> {
constructor(items?: Array<T>) {
super(...items)
Object.setPrototypeOf(this, List.prototype);
}
get first(): T {
return this[0]
}
}
Run Code Online (Sandbox Code Playgroud)
运行良好:
const list = new List([1,2,3]);
console.log(list.first)
Run Code Online (Sandbox Code Playgroud)
但是如果我尝试运行此命令:
const list = new List([1,2,3]);
console.log(list.map(x=>x*2))
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
super(...items)
^
TypeError: Found non-callable @@iterator
Run Code Online (Sandbox Code Playgroud)
理想情况下,我将获得一个对象,该对象等效于new List(this.map(x=>x*2))如何在无需重写Array的所有方法的情况下扩展Array类?
我认为这里的问题是您的List构造函数期望的参数与Array构造函数不同。
当诸如map()创建新数组之类的内置方法时,它们使用在static Symbol.speciesclass属性中找到的构造函数来构造它。默认情况下,这与类构造函数本身相同...除非您重写它。所以List[Symbol.species]是List。并且List.prototype.map()最终会打电话new List(...)。我敢肯定,这些方法所期望的构造,在[Symbol.species]采取相同的参数的Array构造函数,即这些重载之一:
new Array(element0, element1[, ...[, elementN]]); // variadic arguments, one per item in array
new Array(arrayLength); // one numeric argument specifying length
Run Code Online (Sandbox Code Playgroud)
但是您的List构造函数希望将其第一个(也是唯一一个)参数items视为可迭代的(因为它在对的调用中对它使用了扩展语法)super(...items)。list.map(x=>x*2)执行时,它会调用,类似于new List(3),并且您会得到一个关于3不可迭代的错误。
那么,您该怎么做才能解决此问题?到目前为止,最简单的方法是通过使List构造函数ArrayConstructor采用相同的参数类型来确保您的构造函数与该类型兼容。
下一个最简单的操作是重写List[Symbol.species]并返回Array构造函数:
static get [Symbol.species](): ArrayConstructor {
return Array;
}
Run Code Online (Sandbox Code Playgroud)
但这意味着list.map(x => x*2)返回Array而不是List。
假设您确实需要List构造函数接受一个可迭代的参数,而不要使用与相同的可变参数或也许是一个单数的参数Array,并假设您需要list.map()返回a List,则可以List[Symbol.species]用更复杂的方法覆盖该属性:
static get [Symbol.species](): ArrayConstructor {
return Object.assign(function (...items: any[]) {
return new List(new Array(...items))
}, List) as any;
}
Run Code Online (Sandbox Code Playgroud)
从本质上讲,这会导致调用本机方法new List(new Array(x,y,z))而不是new List(x,y,z)。
好的,希望这有意义并给您一些指导。祝好运!
小智 1
无需设置原型。发生错误的原因是构造函数在调用映射时第二次运行,并且数组的长度作为参数传递,因此当您尝试在 super 调用上传播参数时,它会抛出错误,因为数字不可迭代。
constructor(items?: Array<T>) {
console.log(`I've received `, items);
items = items || [];
super(...items);
console.log(`Now i'm this`, this); //
// Object.setPrototypeOf(this, List.prototype);
}
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况?不知道!我还没有足够的积分,否则我会把它作为评论!:-)
如果您将构造函数更改为使用 ... 来收集参数,则不会出现任何问题:
constructor(...items: Array<T>) { //...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
407 次 |
| 最近记录: |