【问题标题】:What is the runtime complexity of JavaScript array spread syntax?JavaScript 数组扩展语法的运行时复杂度是多少?
【发布时间】:2021-05-23 07:21:30
【问题描述】:

假设我想使用数组扩展语法复制现有数组,如下所示:

const a = [1, 2, 3, ..., n];
const b = [...a]

const b = [...a] 的运行时复杂度是多少?我似乎找不到任何相关信息。

【问题讨论】:

  • 旁注:... 不是运算符。操作员不能做... 所做的事情。 ... 是主要语法。
  • 你知道语法的作用吗?你知道“复制数组”的运行时复杂度是多少吗?
  • @Bergi 根据 mdn,扩展语法“允许在零个或多个参数(用于函数调用)或元素(用于数组文字)的地方扩展诸如数组表达式或字符串之类的迭代是预期的”,即在我们的例子中它扩展了数组。所以看起来应该是O(n)。但我不太确定幕后会发生什么 - 如果像 const b = [...a] 这样调用,也许 js 正在做某种优化?
  • @Maksym 是的,就是这样。在引擎盖下它运行迭代器,尽管当然对于数组引擎可能会优化它以不创建迭代器对象并在其上重复调用next()(并且还可以分配具有正确大小的新数组)。它仍然需要将所有元素从一个数组复制到新数组,就像.slice() 一样,即O(n)

标签: javascript algorithm performance ecmascript-6


【解决方案1】:

理论上,这是一些前期成本,然后是线性的(假设是标准数组迭代器,而不是自定义的),因为理论上它是一个循环消耗数组中的迭代器,如下所示:

const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const b = [];
for (const element of a) {
    b[b.length] = element;
}
console.log(b);

这实际上是:

const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const b = [];
{
    const it = a[Symbol.iterator]();
    let result;
    while (!(result = it.next()).done) {
        const element = result.value;
        b[b.length] = element;
    }
}
console.log(b);

(在特定的 [...a] 情况下,即使进行了最小的优化,JavaScript 引擎也可能能够摆脱迭代器开销并使其简单地线性化,就像 a.slice() 那样。)

即使通过 JavaScript 引擎进行了优化(例如,如果它在代码中的热点中),也不清楚它如何比线性做得更好,因为即使内存复制操作也是线性的。

我说 “假设标准数组迭代器” 因为并非所有迭代器都必须是线性的。标准数组迭代器是线性的,但这并不意味着所有的迭代器都是。

【讨论】:

  • FWIW,我在我最近一本书的第 3、5 和 6 章(可能会在其他地方触及它们)中介绍了 ...(rest 和 spread)语法、迭代器、可迭代对象等 JavaScript:新玩具。如果您有兴趣,请在我的个人资料中链接。
  • ……当然,如果您碰巧有一个迭代器,它每步的工作量都在增加(例如,计算素数),它会高于线性。 OP 专门询问了有关复制数组的问题,对于这些,它绝对是线性的。
猜你喜欢
  • 2019-11-23
  • 2014-04-19
  • 2019-06-08
  • 2019-07-15
  • 2018-09-20
  • 1970-01-01
  • 2012-02-04
  • 2020-06-24
相关资源
最近更新 更多