我想一些功能添加到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]
}
}
这个运行良好:
const list = new List([1,2,3]);
console.log(list.first)
但如果我尝试运行此:
const list = new List([1,2,3]);
console.log(list.map(x=>x*2))
我得到以下错误:
super(...items)
^
TypeError: Found non-callable @@iterator
理想情况下,我会得到一个对象返回等效于new List(this.map(x=>x*2))
我如何扩展Array类,而不必重写阵列中的所有方法?
我觉得这里的问题是,你的List
构造并不指望相同的参数Array
构造。
当一个像map()
内置的方法创建一个新的阵列,它们使用在static Symbol.species
class property发现了一个构造函数构造它。这是,默认情况下,相同类的构造函数本身......除非你覆盖它。所以List[Symbol.species]
是List
。而List.prototype.map()
将最终调用new List(...)
。我敢肯定,这些方法期望在[Symbol.species]
构造采取the same arguments as the Array
constructor,这些重载即一个:
new Array(element0, element1[, ...[, elementN]]); // variadic arguments, one per item in array
new Array(arrayLength); // one numeric argument specifying length
但是,你的List
构造函数需要治疗的第一个(也是唯一的)参数items
视为可迭代(因为它使用spread syntax它在调用super(...items)
。当list.map(x=>x*2)
执行它调用像new List(3)
,你会得到一个错误约3
不是迭代。
所以,你能做些什么来解决这个问题?到目前为止,最简单的方法是,以确保您的List
构造与ArrayConstructor
类型兼容,有它采取同样的参数类型。
接下来要做的最简单的事情就是覆盖List[Symbol.species]
并返回Array
构造函数:
static get [Symbol.species](): ArrayConstructor {
return Array;
}
但是,这将意味着list.map(x => x*2)
返回Array
而不是List
。
假设你真的需要你的List
构造采取单一迭代参数,而不是相同的可变参数,或者,也许,一个单数的参数作为Array
,并假设你需要list.map()
返回一个List
,您可以覆盖与List[Symbol.species]
财产更复杂的东西:
static get [Symbol.species](): ArrayConstructor {
return Object.assign(function (...items: any[]) {
return new List(new Array(...items))
}, List) as any;
}
这本质上使本地方法,改为调用new List(new Array(x,y,z))
的new List(x,y,z)
。
好了,希望是有道理的,并给你一些方向。祝好运!
有没有必要设置原型。错误发生,因为构造函数运行时的地图被称为和数组的长度作为参数传递第二次,所以当你试图摊在超级调用的参数,这是因为一些不迭代抛出一个错误。
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);
}
为什么会发生?不知道!我没有足够的积分呢,否则我会把这个作为一个评论! :-)
如果你改变了构造函数使用......收集的参数绝对不会有问题:
constructor(...items: Array<T>) { //...