我有一个用于内部项目的Array子类。我添加的某些方法需要返回一个新数组。我正在尝试找出创建该新数组的最佳方法。
我不想对其进行硬编码以创建特定子类的数组,因为如果其他人对我的类进行子类化,而这就是源数组类,那么它应该创建该子类的对象。换句话说,无论我的下面有多少其他子类,我都想创建一个与当前this
对象相同类的新对象。
Array类本身已经做了类似的事情。如果您对Array进行子类化,然后在子类的实例上使用常规的.map()
函数,它将使用您的类返回一个新的Array。
[为此,ECMAScript规范是here for .map()
使用的.map()
和here for ArraySpeciesCreate()
,但我无法弄清楚这些规范逻辑根据实际的真实Javascript代码转换为什么。
现在,我正在使用:
ArraySpeciesCreate()
并且它似乎在我自己的小世界里工作,但是我想知道.map()
中的所有逻辑是否应该包含比这更多的代码?
FYI,这是ECMAScript规范中的let newArray = new this.constructor();
,应该遵循ArraySpeciesCreate()
来创建它返回的新数组。这大概也是我想要遵循的。
ArraySpeciesCreate()
您将在自己的类中使用哪种实际的Javascript代码来实现此功能?
这是我的Array子类中方法的一个示例:
.map()
该方法中的这一行代码:
是我要问的那个,应该实现// break an array up into chunks
// the last chunk may have fewer items
// returns an array of arrays
chunk(chunkSize) {
if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
throw new TypeError('chunkSize must be a positive integer');
}
const output = new this.constructor();
const numChunks = Math.ceil(this.length / chunkSize);
let index = 0;
for (let i = 0; i < numChunks; i++) {
output.push(this.slice(index, index + chunkSize));
index += chunkSize;
}
return output;
}
逻辑。
我仍然认为您不应该继承const output = new this.constructor();
的子类,但是我可以展示一下ArraySpeciesCreate()
在ECMAScript中实现的外观:
Array
您可能会忽略针对跨领域实例进行测试的怪异案例,但这实际上并不是完全可以正常工作的。 (我怀疑是否存在检查这些内容的好方法,并且似乎无法重现GetFunctionRealm步骤-尽管也许您想对ArraySpeciesCreate
作为本机函数进行检查)]]
[通常,它只涉及访问if (!Array.isArray(this)) // if not called on an array
return new Array(len);
const {constructor} = this;
if (typeof constructor == "function" // if the constructor looks like a constructor,
&& !Function.prototype.isPrototypeOf(constructor) // but appears to stem from a
// different realm (iframe etc)
&& constructor.name == "Array") // and might be that realm's builtin Array
return new Array(len);
const C = constructor?[Symbol.species];
if (C == null) // if there's no subclass species
return new Array(len);
return new C(len);
上的constructor
,并使用该结果而不是当前类来构造新实例。