For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-bulk-add-array-elements.md.
  • 简体中文
  • Bulk-add array elements S1

    中文标题:批量添加数组元素

    提案概览
    提案速览

    该提案引入 Array.prototype.pushAll,用于将可迭代对象的所有元素追加到数组,解决了使用展开语法调用 push 时的冗长问题和栈溢出风险。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    Array.prototype.pushAll

    本提案为数组引入一个新方法,用于将可迭代对象中的所有元素推入数组末尾。

    状态

    状态:Stage 0

    提案发起人:Daniel Rosenwasser (@DanielRosenwasser)

    更多信息请参阅 TC39 提案流程

    动机

    目前,将另一个可迭代对象中的多个元素追加到数组末尾,最惯用且最简洁的方式是使用 Array.prototype.push 结合参数展开语法(...arg):

    const arr = [1, 2, 3];
    const newElements = [4, 5, 6];
    arr.push(...newElements);

    这种模式通常有效,但也存在一些缺点。 有人认为这种写法并不完全直观或易于发现,尤其是对于 JavaScript 新手或不熟悉展开语法的人来说。 但 .push(...arg) 最关键的问题在于:当 arg 是一个非常大的可迭代对象时,存在栈溢出的风险,因为参数展开语法会将所有元素展开为单独的参数。 这种担忧并非凭空臆测;现实中已经出现过因此导致运行时错误的实例(例如,参见 Node.js 用户报告的这个问题)。

    在这些情况下,可能会改用循环或 forEach 调用逐一 push 每个元素。

    for (const item of newElements) {
      arr.push(item);
    }

    这段代码可以说更加明确,但对于这种常见操作而言也更为冗长。 而且在新增元素来自大小已知的数组时,这种写法可能无法实现最优优化。 当 push 的元素足够多时,数组的底层存储可能需要扩容,并导致中间多次重新分配。 理想情况下,如果新增元素的数量已知且超过可用存储空间,运行时可以只重新分配一次。

    拟议解决方案

    本提案建议新增一个方法 Array.prototype.pushAll,以便用更简洁、更易读的方式将可迭代对象中的所有元素追加到数组。 该方法可以(大致)通过如下方式实现 polyfill:

    Array.prototype.pushAll = function(iterable) {
      for (const item of iterable) {
        this.push(item);
      }
    };
    NOTE

    有一些边界情况需要考虑,例如在操作过程中数组被修改(例如将目标数组本身作为参数传入)。 这类情况的确切语义可能需要对数组输入做特殊处理,但可以在后续阶段明确。

    有了这个新方法,前面的示例可以改写为:

    const arr = [1, 2, 3];
    const newElements = [4, 5, 6];
    arr.pushAll(newElements);

    现有先例

    许多其他语言都有类似的方法,用于将多个元素追加到可增长的列表类型。 下表展示了若干流行语言如何处理此操作: