JS数组降维实现:从循环到Array.prototype.concat.apply

作者:青山有信

时间:2026-10-23

浏览:496

本文深入解析JavaScript中将多维数组(特别是二维数组)转换为一维数组的三种常见实现方式。通过对比传统的双重循环、利用concat方法的单重循环,以及Vue源码中Array.prototype.concat.apply的高阶用法,详细阐述各方法的原理与性能差异。文章结合Vue2.6.11版本源码,展示了如何在实际工程中应用这些技巧,并探讨了递归处理深层嵌套数组的场景,帮助开发者理解底层逻辑并优化代码结构。

文章目录

引言与背景

在业务开发中,将多维数组(尤其是二维数组)转换为一维数组是一项基础且高频的操作。近期在研读Vue2.6.1.1版本源码时,发现了源码处理二维数组降维的精妙代码,特此整理此文进行记录与复盘,以加深理解。

二维数组降为一维数组

双重循环降维法

循环降维


let children = [1, 2, 3, [4, 5, 6], 7, 8, [9, 10]];
function simpleNormalizeChildren(children) {
 let reduce = [];
 for (let i = 0; i < children.length; i++) {
  if (Array.isArray(children[i])) {
   for (let j = 0; j < children[i].length; j++) {
    reduce.push(children[i][j]);
   }
  } else {
   reduce.push(children[i]);
  }
 }
 return reduce;
}
simpleNormalizeChildren(children) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

该方法思路直观,核心逻辑是通过双重循环遍历二维数组中的每一个元素,并将其逐一添加到新数组中。

利用concat方法简化循环

concat降维

MDN上对于concat的介绍

“concat creates a new array consisting of the elements in the object on which it is called, followed in order by, for each argument, the elements of that argument (if the argument is an array) or the argument itself (if the argument is not an array).”

concat

concat方法的特性在于:若参数为单个元素,则直接将其插入新数组;若参数为数组,则将该数组的各个元素依次插入新数组。基于此特性,我们可以优化代码实现:


let children = [1, 2, 3, [4, 5, 6], 7, 8, [9, 10]];
function simpleNormalizeChildren(children) {
 let reduce = [];
 for (let i = 0; i < children.length; i++) {
  reduce = reduce.concat(children[i]);
 }
 return reduce;
}
simpleNormalizeChildren(children) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

当children作为concat方法的参数时,若其本身是数组,则数组内的每个子元素会被独立插入到新数组中。借助concat方法,我们将原本的双重循环简化为了单重循环。

结合apply与concat的高阶用法

apply和concat降维

MDN上对于apply方法的介绍

“The apply() method calls a function with a given this value and arguments provided as an array.”

apply

apply方法用于调用一个函数,其第一个参数指定被调用函数的this值,第二个参数(数组或类数组对象)则作为该函数的arguments。这意味着数组中的每个元素会依次成为被调用函数的独立参数。将此特性应用于代码中:


let children = [1, 2, 3, [4, 5, 6], 7, 8, [9, 10]];
function simpleNormalizeChildren(children) {
 return Array.prototype.concat.apply([], children);
}
simpleNormalizeChildren(children) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

当children作为apply方法的第二个参数(本身为数组)时,数组中的每个元素(即二维数组的第二维数组)会被依次作为参数传入concat函数。其效果等同于执行[].concat(1, 2, 3, [4, 5, 6], 7, 8, [9, 10])。利用apply方法,我们将单重循环进一步精简为一行代码。

Vue源码中的递归降维实现

Vue2.6.11版本源码降维


let children = [1, 2, 3, [4, 5, 6], 7, 8, [9, 10]];
// :any 可以去掉 这里是Vue通过Flow指定传入的参数类型可以是任意类型
function simpleNormalizeChildren(children: any) {
 for (let i = 0; i < children.length; i++) {
  if (Array.isArray(children[i])) {
   return Array.prototype.concat.apply([], children);
  }
 }
 return children;
}

simpleNormalizeChildren(children); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

多维数组降为一维数组

递归降维

递归函数是指在函数体内调用自身;

使用递归函数时,必须注意设置终止条件以避免死循环;


// 多维数组
let children = [1, [2,3], [4, [5, 6, [7, 8]]], [9, 10]];
function simpleNormalizeChildren(children) {
 for (let i = 0; i < children.length; i++) {
  if (Array.isArray(children[i])) {
   children = Array.prototype.concat.apply([], children);
   for(let j =0; j<children.length; j++) {
    simpleNormalizeChildren(children)
   }
  }
 }
 return children;
}
simpleNormalizeChildren(children); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

至此,关于JS数组降维实现Array.prototype.concat.apply([], arr)的介绍已完毕。如需了解更多JS数组降维相关内容,请搜索本站历史文章或继续浏览下方相关文章,感谢大家的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章