扩展数组时发现不可调用的@@iterator
Found non-callable @@iterator when extending Array
当我尝试扩展数组时 class:
class Collection extends Array {
constructor(array){
super(...array)
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(dates)
console.log(test[Symbol.iterator]); //Iterator exists
console.log(test.min()); ///Error: Found non-callable @@iterator
出于某种原因出现此错误,但是当我们这样做时:
class Collection extends Array {
static from(array){ /// Using a Factory instead of a constructor
return new Collection(...array)
}
...
...
}
const test = Collection.from(dates)
console.log(test.min()); //returns the Date
一切正常。为什么构造函数的迭代器有问题??
问题是 array.map() return 是一个 new 数组,并且会调用您的构造函数来完成此操作。
可以在此处看到此行为:
class CustomArray extends Array {
constructor(...args) {
super(...args)
console.log('constructor called')
}
}
const myArray = new CustomArray(1, 2, 3)
console.log('call .map()')
myArray.map(x => x)
因为您的自定义构造函数不采用与默认数组构造函数相同的参数,所以 .map() 函数在尝试使用它时会出错。以下实现将为您工作,因为它更改了构造函数以采用 .map() 期望的参数。
class Collection extends Array {
constructor(...args){
super(...args)
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(...dates)
console.log(test.min());
也许这不是您想要的,因为您可能想要更改构造函数的行为。事实证明,Javascript 为数组提供了一个特殊的 species symbol,专门用于帮助像您所做的那样制作数组 subclasses。你可以给这个物种符号一个不同的构造函数来使用,像 .map()
这样的函数将使用这个物种符号提供的任何东西。
class Collection extends Array {
constructor(array){
super(...array)
}
static [Symbol.species](...args) {
return new Collection(args)
}
static get [Symbol.species]() {
return function(...args) {
return new Collection(args)
}
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(dates)
console.log(test.min());
这使用了很多技巧,所以我建议尽可能避免使用这种特定的解决方案。但是,基本思想是物种 属性 应该设置为 class,然后将由 .map() 等函数更新。在上面的示例中,我将 species
属性 设置为 getter (否则我无法使其正常工作 - 我认为这与它的默认值设置方式有关).这个 getter returned 函数,在这种情况下会像 class 一样工作(您不必使用 class 关键字来创建 class).当一个普通函数被更新时,我只是 return 集合的一个实例 class,正确构造(即使这个匿名函数是正在构造的东西,它可以 return 完全不同的东西) .
当我尝试扩展数组时 class:
class Collection extends Array {
constructor(array){
super(...array)
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(dates)
console.log(test[Symbol.iterator]); //Iterator exists
console.log(test.min()); ///Error: Found non-callable @@iterator
出于某种原因出现此错误,但是当我们这样做时:
class Collection extends Array {
static from(array){ /// Using a Factory instead of a constructor
return new Collection(...array)
}
...
...
}
const test = Collection.from(dates)
console.log(test.min()); //returns the Date
一切正常。为什么构造函数的迭代器有问题??
问题是 array.map() return 是一个 new 数组,并且会调用您的构造函数来完成此操作。
可以在此处看到此行为:
class CustomArray extends Array {
constructor(...args) {
super(...args)
console.log('constructor called')
}
}
const myArray = new CustomArray(1, 2, 3)
console.log('call .map()')
myArray.map(x => x)
因为您的自定义构造函数不采用与默认数组构造函数相同的参数,所以 .map() 函数在尝试使用它时会出错。以下实现将为您工作,因为它更改了构造函数以采用 .map() 期望的参数。
class Collection extends Array {
constructor(...args){
super(...args)
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(...dates)
console.log(test.min());
也许这不是您想要的,因为您可能想要更改构造函数的行为。事实证明,Javascript 为数组提供了一个特殊的 species symbol,专门用于帮助像您所做的那样制作数组 subclasses。你可以给这个物种符号一个不同的构造函数来使用,像 .map()
这样的函数将使用这个物种符号提供的任何东西。
class Collection extends Array {
constructor(array){
super(...array)
}
static [Symbol.species](...args) {
return new Collection(args)
}
static get [Symbol.species]() {
return function(...args) {
return new Collection(args)
}
}
getTimes(){
return this.map(value=> value.getTime())
}
min(){
return new Date(Math.min(...this.getTimes()))
}
}
const array = ['2000/02/01','2000/02/02']
const dates = array.map(value => new Date(value))
const test = new Collection(dates)
console.log(test.min());
这使用了很多技巧,所以我建议尽可能避免使用这种特定的解决方案。但是,基本思想是物种 属性 应该设置为 class,然后将由 .map() 等函数更新。在上面的示例中,我将 species
属性 设置为 getter (否则我无法使其正常工作 - 我认为这与它的默认值设置方式有关).这个 getter returned 函数,在这种情况下会像 class 一样工作(您不必使用 class 关键字来创建 class).当一个普通函数被更新时,我只是 return 集合的一个实例 class,正确构造(即使这个匿名函数是正在构造的东西,它可以 return 完全不同的东西) .