自定义类扩展 Array 而不使用扩展语法
Posted
技术标签:
【中文标题】自定义类扩展 Array 而不使用扩展语法【英文标题】:Custom class extending Array without using spread syntax 【发布时间】:2020-12-29 12:14:12 【问题描述】:几年来,我一直在构建和使用 javascript 中的自定义数据分析工具(repo、docs)。
我最近所做的更改之一是使用 JavaScript 类来扩展本机 Array
类型,因此我可以轻松地将我的自定义函数调用为类数组对象上的方法,而不是将它们传递给那些用作参数,而不会失去使用 []
表示法访问元素的能力。
为此,我一直在使用以下代码:
class AnalyserRows extends Array
constructor(sourceArray)
super(...sourceArray);
// ...
这已经运行了一段时间,但最近我尝试加载特别大的数据集,但遇到了问题。我试图创建一个包含大约 66,000 个元素的 AnalyserRows
对象,但 Chrome 会抛出此错误:
未捕获的 RangeError:超出最大调用堆栈大小
在我的搜索中,我发现了这个问题的解释: RangeError - Maximum Call Stack Size Exceeded Error Using Spread Operator in Node.js / Javascript
扩展运算符(和 Array.assign)将整个源数组加载到堆栈中,然后将其推送到目标数组中。一旦源数组超过 125,052,就会导致堆栈溢出/范围错误。
所以现在我的问题是如何在自定义类的 constructor
中调用 super
并在不使用扩展运算符的情况下传递源数组的每个元素?
可以创建一个包含这么多元素的Array
而没有任何真正的问题,所以我觉得应该可以用像这样扩展Array
的类来做同样的事情。但是如果不使用扩展运算符或进行一些其他更改以阻止我使用我一直在使用的某些语法,我不知道该怎么做。
【问题讨论】:
你是怎么打电话给AnalyserRows
的?顺便说一句I doubt this subclass works at all.
“rows”是一个现有的数组,我这样称呼它:dataConfig.rows = new AnalyserRows(rows);
它确实有效。在遇到这个问题之前,我已经使用了很长时间。现在刚刚检查,我可以调用常规的Array
方法,如map
和reduce
没问题。
也许你也定义了static [Symbol.species] = Array
?
不。我知道只有当您希望Array
的本机方法通常返回一个新的Array
(如map
和reduce
)仍然返回一个Array
时才需要这样做。我不想那样。如果您有兴趣查看代码,我将链接到我的问题中的 repo。有问题的文件是 analyser.js
通过扩展语法调用,new AnalyserRows([]).map(x => x)
确实为我抛出了 TypeError: Found non-callable @@iterator
- 就像在链接的问题中一样。使用super(sourceArray.length)
,它将返回AnalyserRows [undefined]
(长度为1),因为您将undefined
传递给超级调用。不知道为什么不能重现?
【参考方案1】:
Array
构造函数有两种形式:您可以将所有数组元素传递给它,也可以将数组的大小传递给它。您可以尝试使用第二种形式,然后在构造函数中复制数组元素。
class AnalyserRows extends Array
constructor(sourceArray)
super(sourceArray.length);
for (let i = 0; i < sourceArray.length; i++)
this[i] = sourceArray[i];
// ...
但是,对于大型数组,这可能会非常慢。从您给出的报价来看,听起来任何内置快捷方式都会遇到堆栈溢出问题。
【讨论】:
感谢 Barmar,我刚刚尝试过,它确实有效。很简单的解决方案,既然你已经提出了建议,我觉得自己没有想到它很傻!使用这种方法创建 66,000 个元素的数组看起来只需要 2.4 毫秒,至少对于这个示例数据来说,所以我现在不太担心它太慢。以上是关于自定义类扩展 Array 而不使用扩展语法的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Typescript 使用自定义方法实现类数组类?