百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

12种JavaScript中最常用的数组操作整理汇总

myzbx 2025-07-03 18:18 2 浏览

数组是最常见的数据结构之一,我们需要绝对自信地使用它。在这里,我将列出 JavaScript 中最重要的几个数组常用操作片段,包括数组长度、替换元素、去重以及许多其他内容。

1、数组长度

大多数人都知道可以像这样得到数组的长度:

const arr = [1, 2, 3]; 

console.log(arr.length); // 3

有趣的是,我们可以手动修改长度。这就是我所说的:

const arr = [1, 2, 3]; 

arr.length = 2; 

arr.forEach(i => console.log(i)); // 1 2

甚至创建指定长度的新数组:

const arr = []; 

arr.length = 100; 

console.log(arr) // [undefined, undefined, undefined ...]

这不是一个很好的实践,但是值得了解。

我们常常需要清空数组时候会使用:

const arr = [1, 2]; 

arr.length = 0; 

console.log(arr)  // []

如果 arr 的值是共享的,并且所有参与者都必须看到清除的效果,那么这就是你需要采取的方法。

但是,JavaScript 语义规定,如果减少数组的长度,则必须删除新长度及以上的所有元素。

而且这需要花费时间(除非引擎对设置长度为零的特殊情况进行了优化)。实际上,一个性能测试表明,在所有当前的 JavaScript 引擎上,这种清除方法更快。

2、替换数组元素

有几种方法可以解决这个问题。如果需要替换指定索引处的元素,请使用 splice:

const arr = [1, 2, 3]; 

arr.splice(2, 1, 4); // 将索引 2 开始的 1 元素更改为 4

console.log(arr); // [1, 2, 4] 

arr.splice(0, 2, 5, 6) // 将索引 0 开始的 2 个元素更改为 5 和 6 

console.log(arr); // [5, 6, 4]

splice 在数组删除有更多的说明

如果你需要根据项目的内容替换项目,或者必须创建一个新数组,请使用 map:

const arr = [1, 2, 3, 4, 5, 6]; 

// 所有奇数的平方

const arr2 = arr.map(item => item % 2 == 0 ? item : item*item); 

console.log(arr2); // [1, 2, 9, 4, 25, 6];

map 接受函数作为其参数。它将对数组中的每个元素调用该函数一次,并生成一个新的函数返回的项数组。

关于 map 有个经典的面试题:['1', '2', '3', '4', '5'].map(parseInt) => ?

3、过滤数组

在某些情况下,你需要删除数组中的某些元素,然后创建一个新的元素。在这种情况下,使用在ES5中引入的很棒的 filter 方法:

const arr = [1, 2, 3, 4, 5, 6, 7]; 

// 过滤掉所有奇数

const arr2 = arr.filter(item => item % 2 == 0); 

console.log(arr2); // [2, 4, 6];

filter 的工作原理与 map 非常相似。向它提供一个函数,filter 将在数组的每个元素上调用它。如果要在新数组中包含此特定元素,则函数必须返回 true,否则返回 false。

4、 合并数组

如果你想将多个数组合并为一个数组,有两种方法。

Array 提供了 concat 方法:

const arr1 = [1, 2, 3]; 

const arr2 = [4, 5, 6]; 

const arr3 = arr1.concat(arr2);

console.log(arr3 ); // [1, 2, 3, 4, 5, 6]

ES6 中引入了 spread operator,一种更方便的方法:

const arr1 = [1, 2, 3]; 

const arr2 = [4, 5, 6]; 

const arr3 = [...arr1, ...arr2];

console.log(arr3 ); // [1, 2, 3, 4, 5, 6]

还有一种比较奇特方法:

const arr1 = [1, 2, 3]; 

const arr2 = [4, 5, 6]; 

Array.prototype.push.apply(arr1, arr2);

console.log(arr1); // [1, 2, 3, 4, 5, 6]

上面 2 种通用的方法,都不会改变原数组,最后一种奇特方法,会改变 push 的原数组,谨慎使用。

Array.prototype.push.apply 和 concat 对比:

  • 数据上万情况下,两者性能相差毫秒个位数级别
  • Array.prototype.push.apply 数组长度有限制,不同浏览器不同,一般不能超过十万, concat 无限制
  • Array.prototype.push.apply 会改变原数组, concat 不会

正常情况下我们都应该使用 concat 和 spread operator,有种情况下可以使用,如果频繁合并数组可以用 Array.prototype.push.apply。

5、复制数组

总所周知,定义数组变量存储不是数组值,而只是存储引用。 这是我的意思:

const arr1 = [1, 2, 3]; 

const arr2 = arr1; 

arr2[0] = 4; 

arr2[1] = 2; 

arr2[2] = 0; 

console.log(arr1); // [4, 2, 0]

因为 arr2 持有对 arr1 的引用,所以对 arr2 的任何更改都是对 arr1 的更改。

const arr1 = [1, 2, 3]; 

const arr2 = arr1.slice(0); 

arr2[0] = 4; 

arr2[1] = 2; 

arr2[2] = 0;

console.log(arr1); // [1, 2, 3]

console.log(arr2); // [4, 2, 0]

我们也可以使用 ES6 的 spread operator:

const arr1 = [1, 2, 3]; 

const arr2 = [...arr1]; 

arr2[0] = 4; 

arr2[1] = 2; 

arr2[2] = 0;

console.log(arr1); // [1, 2, 3]

console.log(arr2); // [4, 2, 0]

也可以使用前面合并使用的 concat 方法

const arr1 = [1, 2, 3]; 

const arr2 = [].concat(arr1); 

arr2[0] = 4; 

arr2[1] = 2; 

arr2[2] = 0;

console.log(arr1); // [1, 2, 3]

console.log(arr2); // [4, 2, 0]

注意:如果想要了解更多的数组复制,请查询 数组深拷贝和浅拷贝 相关资料,这里只实现了浅拷贝。

6、数组去重

数组去重是面试经常问的,数组去重方式很多,这里介绍比较简单直白的三种方法:

可以使用 filter 方法帮助我们删除重复数组元素。filter 将接受一个函数并传递 3 个参数:当前项、索引和当前数组。

const arr1 = [1, 1, 2, 3, 1, 5, 9, 4, 2]; 

const arr2 = arr1.filter((item, index, arr) => arr.indexOf(item) == index);

console.log(arr2); // [1, 2, 3, 5, 9, 4]

可以使用 reduce 方法从数组中删除所有重复项。然而,这有点棘手。reduce 将接受一个函数并传递 2 个参数:数组的当前值和累加器。

累加器在项目之间保持相同,并最终返回:

const arr1 = [1, 1, 2, 3, 1, 5, 9, 4, 2]; 

const arr2 = arr1.reduce(

  (acc, item) =>  acc.indexOf(item) == -1 ? [...acc, item]: acc,

  []   // 初始化当前值

);

console.log(arr2); // [1, 2, 3, 5, 9, 4]

可以使用 ES6 中引入的新数据结构 set 和 spread operator:

const arr1 = [1, 1, 2, 3, 1, 5, 9, 4, 2]; 

const arr2 = [...(new Set(arr1))]; 

console.log(arr2); // [1, 2, 3, 5, 9, 4]

还有很多其他去重方式,比如使用 {} + for。

7、转换为数组

有时我们必须将一些其它数据结构,如集合或字符串转换为数组。

类数组:函数参数,dom 集合

Array.prototype.slice.call(arguments);

Array.prototype.concat.apply([], arguments);

字符串:

console.log('string'.split('')); // ["s", "t", "r", "i", "n", "g"]

console.log(Array.from('string'));  // ["s", "t", "r", "i", "n", "g"]

集合:

console.log(Array.from(new Set(1,2,3))); // [1,2,3]

console.log([...(new Set(1,2,3))]); // [1,2,3]

8、数组遍历

数组遍历方式很多,有底层的,有高阶函数式,我们就来介绍几种:

for:

const arr = [1, 2, 3]; 

for (let i = 0; i < arr.length; i++) { 

  console.log(arr[i]); 

} 

// 1 2 3

for-in:

const arr = [1, 2, 3]; 

for (let i in arr) {

   if(arr.hasOwnProperty(i)) {

      console.log(arr[i]); 

  }

} 

// 1 2 3

for-of:

const arr = [1, 2, 3]; 

for (let i of arr) {

  console.log(i); 

} 

// 1 2 3

forEach:

[1, 2, 3].forEach(i => console.log(i))

// 1 2 3

while:

const arr = [1,2,3];

let i = -1;

const length = arr.length;

while(++i < length) {

    console.log(arr[i])

}

// 1 2 3

迭代辅助语句:break 和 continue

  • break 语句是跳出当前循环,并执行当前循环之后的语句
  • continue 语句是终止当前循环,并继续执行下一次循环

上面方式中,除了 forEach 不支持跳出循环体,其他都支持。高阶函数式方式都类似 forEach 。

性能对比:

while > for > for-of > forEach > for-in

如果是编写一些库或者大量数据遍历,推荐使用 while。有名的工具库 lodash 里面遍历全是 while。正常操作,for-of 或者 forEach 已经完全满足需求。

下面介绍几种高级函数式,满足条件为 true 立即终止循环,否则继续遍历到整个数组完成的方法:

// ES5

[1, 2, 3].some((i) => i == 1);

// ES6

[1, 2, 3].find((i) => i == 1);

[1, 2, 3].findIndex((i) => i == 1);

其他高阶函数式方法,例如 forEach map filter reduce reduceRight every sort 等,都是把整个数组遍历。

9、扁平化多维数组

这个功能说不是很常用,但是有时候又会用到:

二维数组:

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

const arr2 = [].concat.apply([], arr1);

console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

三维数组:

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [[1, 2, 3], [4, 5, 6], [7, 8, 9]]];

const arr2 = [].concat.apply([], arr1);

console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, [1, 2, 3], [4, 5, 6], [7, 8, 9]]

concat.apply 方式只能扁平化二维数组,在多了就需要递归操作。

function flatten(arr) {

  return arr.reduce((flat, toFlatten) => {

    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);

  }, []);

}

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [[1, 2, 3], [4, 5, 6], [7, 8, 9]]];

const arr2 = flatten(arr1);

console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ES6+(ES2019) 给我们提供一个 flat 方法:

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

const arr2 = arr1.flat();

console.log(arr2); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

默认只是扁平化二维数组,如果想要扁平化多维,它接受一个参数 depth,如果想要展开无限的深度使用 Infinity:

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [[1, 2, 3], [4, 5, 6], [7, 8, 9]]];

const arr2 = arr1.flat(Infinity);

console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]

还有一种面试扁平化二维数组方式:

const arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [[1, 2, 3], [4, 5, 6], [7, 8, 9]]];

const arr2 = arr1.toString().split(',').map(n => parseInt(n, 10));

console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]

10、数组添加

如何从数组中添加元素?

我们可以使用 push 从数组末尾添加元素,使用 unshift 从开头添加元素,或者使用 splice 从中间添加元素。concat 方法可创建带有所需项目的新数组,这是一种添加元素的更高级的方法。

从数组的末尾添加元素:

const arr = [1, 2, 3, 4, 5, 6];

arr.push(7)

console.log( arr ); // [1, 2, 3, 4, 5, 6, 7]

从数组的开头添加元素:

const arr = [1, 2, 3, 4, 5, 6];

arr.unshift(0)

console.log( arr ); // [0, 1, 2, 3, 4, 5, 6]

push 方法的工作原理与 unshift 方法非常相似,方法都没有参数,都是返回数组更新的 length 属性。它修改调用它的数组。

使用 splice 添加数组元素:

只需要把 splice,第二个参数设为 0 即可,splice 在数组删除有更多的说明

const arr = [1, 2, 3, 4, 5];

arr.splice(1, 0, 10)

console.log(arr); // [1, 10, 2, 3, 4, 5]

使用 concat 添加数组元素:

const arr1 = [1, 2, 3, 4, 5];

const arr2 = arr1.concat(6);

console.log(arr2); // [1, 2, 3, 4, 5, 6]

11、数组删除

数组允许我们对值进行分组并对其进行遍历。 我们可以通过不同的方式添加和删除数组元素。 不幸的是,没有简单的 Array.remove 方法。

那么,如何从数组中删除元素?

除了 delete 方式外,JavaScript 数组还提供了多种清除数组值的方法。

我们可以使用 pop 从数组末尾删除元素,使用 shift 从开头删除元素,或者使用 splice 从中间删除元素。

filter 方法可创建带有所需项目的新数组,这是一种删除不需要的元素的更高级的方法。

从数组的末尾删除元素:

通过将 length 属性设置为小于当前数组长度,可以从数组末尾删除数组元素。 索引大于或等于新长度的任何元素都将被删除。

const arr = [1, 2, 3, 4, 5, 6];

arr.length = 4; 

console.log( arr ); // [1, 2, 3, 4]

pop 方法删除数组的最后一个元素,返回该元素,并更新length属性。pop 方法会修改调用它的数组,这意味着与使用 delete 不同,最后一个元素被完全删除并且数组长度减小。

const arr = [1, 2, 3, 4, 5, 6];

arr.pop(); 

console.log( arr ); // [1, 2, 3, 4, 5]

从数组的开头删除元素:

shift 方法的工作原理与 pop 方法非常相似,只是它删除了数组的第一个元素而不是最后一个元素。

const arr = [1, 2, 3, 4, 5, 6];

arr.shift(); 

console.log( arr ); // [2, 3, 4, 5, 6]

shift 和 pop 方法都没有参数,都是返回已删除的元素,更新剩余元素的索引,并更新 length 属性。它修改调用它的数组。如果没有元素,或者数组长度为 0,该方法返回 undefined。

使用 splice 删除数组元素:

splice 方法可用于从数组中添加、替换或删除元素。

splice 方法接收至少三个参数:

  • start:在数组中开始删除元素的位置
  • deleteCount:删除多少个元素(可选)
  • items...:添加元素(可选)

splice 可以实现添加、替换或删除。

删除:

如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。

如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。

如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。

const arr1 = [1, 2, 3, 4, 5];

arr1.splice(1);   

console.log(arr1); // [1];

const arr2 = [1, 2, 3, 4, 5];

arr2.splice(1, 2) 

console.log(arr2); // [1, 4, 5]

const arr3 = [1, 2, 3, 4, 5];

arr3.splice(1, 1) 

console.log(arr3); // [1,3, 4, 5]

添加:

添加只需要把 deleteCount 设置为 0,items 就是要添加的元素。

const arr = [1, 2, 3, 4, 5];

arr.splice(1, 0, 10)

console.log(arr); // [1, 10, 2, 3, 4, 5]

替换:

添加只需要把 deleteCount 设置为和 items 个数一样即可,items 就是要添加的元素。

const arr = [1, 2, 3, 4, 5];

arr.splice(1, 1, 10)

console.log(arr); // [1, 10, 3, 4, 5]

注意:splice 方法实际上返回两个数组,即原始数组(现在缺少已删除的元素)和仅包含已删除的元素的数组。如果循环删除元素或者多个相同元素,最好使用倒序遍历。

使用 delete 删除单个数组元素:

使用 delete 运算符不会影响 length 属性。它也不会影响后续数组元素的索引。数组变得稀疏,这是说删除的项目没有被删除而是变成 undefined 的一种奇特的方式。

const arr = [1, 2, 3, 4, 5];

delete arr[1]

console.log(arr); // [1, empty, 3, 4, 5]

实际上没有将元素从数组中删除的原因是 delete 运算符更多的是释放内存,而不是删除元素。 当不再有对该值的引用时,将释放内存。

使用数组 filter 方法删除匹配的元素:

与 splice 方法不同,filter 创建一个新数组。

filter 接收一个回调方法,回调返回 true 或 false。返回 true 的元素被添加到新的经过筛选的数组中。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];

const filtered = arr.filter((value, index, arr) => value > 5);

console.log(filtered); // [6, 7, 8, 9]

console.log(arr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

清除或重置数组:

最简单和最快的技术是将数组变量设置为空数组

let arr = [1,2,3];

arr = [];

清除数组的一个简单技巧是将其 length 属性设置为 0。

let arr = [1,2,3];

arr.length = 0;

使用 splice 方法,不传递第二个参数。这将返回原始元素的一个副本,这对于我们的有些场景可能很方便。也是一种数组复制方法技巧。

let arr = [1,2,3];

arr.splice(0);

使用 while 循环,这不是一种常用清除数组的方法,但它确实有效,而且可读性强。一些性能测试也显示这是最快的技术。

const arr = [1, 2, 3, 4, 5, 6];

while (arr.length) { arr.pop(); }

console.log(arr); // []

12、其他方法

剔除假值:

[1, false, '', NaN, 0, [], {}, '123'].filter(Boolean) // [1, [], {}, '123']

是否有一个真值:

[1, false, '', NaN, 0, [], {}, '123'].some(Boolean)  // true

是否全部都是真值:

[1, false, '', NaN, 0, [], {}, '123'].every(Boolean) // false

补零:

Array(6).join('0');      // '00000'  注意:如果要补5个0,要写6,而不是5。

Array(5).fill('0').join('')  // '00000'

数组最大值和最小值:

Math.max.apply(null, [1, 2, 3, 4, 5])  // 5

Math.min.apply(null, [1, 2, 3, 4, 5])  // 1

判断回文字符串:

const str1 = 'string';

const str2 = str1.split('').reverse().join('');

console.log(str1 === str2); // false

数组模拟队列:

队列先进先出:

const arr = [1];

// 入队

arr.push(2); 

console.log('入队元素:', arr[arr.length -1]); // 2

// 出队

console.log('出队元素:', arr.shift()); // 1

获取数组最后一个元素:

像我们平常都是这样来获取:

const arr = [1, 2, 3, 4, 5];

console.log(arr[arr.length - 1]);   // 5 

感觉很麻烦,不过 ES 有了提案,未来可以通过 arr[-1] 这种方式来获取,Python 也有这种风骚的操作:

目前我们可以借助 ES6 的 Proxy 对象来实现:

const arr1 = [1, 2, 3, 4, 5];

function createNegativeArrayProxy(array) {

    if (!Array.isArray(array)) {     

       throw new TypeError('Expected an array'); 

    }

    return new Proxy(array, {

      get: (target, prop, receiver) => { 

        prop = +prop;

        return Reflect.get(target, prop < 0 ? target.length + prop : prop, receiver);; 

      }    

    })

}

const arr2 = createNegativeArrayProxy(arr1);

console.log(arr1[-1]) // undefined

console.log(arr1[-2]) // undefined

console.log(arr2[-1]) // 5

console.log(arr2[-2]) // 4

注意:这样方式虽然有趣,但是会引起性能问题,50万次循环下,在Chrome浏览器,代理数组的执行时间大约为正常数组的50倍,在Firefox浏览器大约为20倍。在大量循环情况下,请慎用。无论是面试还是学习,你都应该掌握 Proxy 用法。

相关推荐

C语言速成之数组:C语言数据处理的核心武器,你真的玩透了吗?

程序员Feri一名12年+的程序员,做过开发带过团队创过业,擅长Java、鸿蒙、嵌入式、人工智能等开发,专注于程序员成长的那点儿事,希望在成长的路上有你相伴!君志所向,一往无前!数组:C语言数据处理...

ES6史上最全数JS数组方法合集-02-数组操作

数组生成array.ofletres=Array.of(1,2,3)console.log(res)//[1,2,3]下标定位indexOf用于查找数组中是否存在某个值,如果存...

前端性能拉胯?这 8 个 JavaScript 技巧让你的代码飞起来!

在前端开发的江湖里,JavaScript就是我们手中的“绝世宝剑”。但为啥别人用剑就能轻松斩敌,你的代码却总拖后腿,页面加载慢、交互卡顿?别着急!今天带来8个超实用的JavaScript实...

12种JavaScript中最常用的数组操作整理汇总

数组是最常见的数据结构之一,我们需要绝对自信地使用它。在这里,我将列出JavaScript中最重要的几个数组常用操作片段,包括数组长度、替换元素、去重以及许多其他内容。1、数组长度大多数人都知道可...

手把手教你在Webpack写一个Loader

前言有的时候,你可能在从零搭建Webpack项目很熟悉,配置过各种loader,面试官在Webpack方面问你,是否自己实现过一个loader?如果没有去了解过如果去实现,确实有点尴尬,其...

const关键字到底该什么用?(可以用const关键字定义变量吗)

文|守望先生经授权转载自公众号编程珠玑(id:shouwangxiansheng)前言我们都知道使用const关键字限定一个变量为只读,但它是真正意义上的只读吗?实际中又该如何使用const关键字...

“JavaScript变量声明三兄弟,你真的会用吗?

在JavaScript中,var、let和const是声明变量的关键字,它们在作用域、变量提升、重复声明和重新赋值等方面有显著区别。以下是它们的相同点和不同点,并通过代码示例详细说明。一、相同点声明变...

ES6(二)let 和 const(es6 var let const区别)

let命令let和var差不多,只是限制了有效范围。先定义后使用不管是什么编程语言,不管语法是否允许,都要秉承先定义,然后再使用的习惯,这样不会出幺蛾子。以前JavaScript比较随意,...

js 里面 let 和 const的区别(js中的let)

在JavaScript(包括Vue、Node.js、前端脚本等)中,const和let是用于声明变量的两种方式,它们的主要区别如下:constvslet的区别特性constlet是否...

JDK21新特性:Sequenced Collections

SequencedCollectionsJDK21在JEP431提出了有序集合(SequencedCollections)。引入新的接口来表示有序集合。这样的集合都有一个明确的第一个元素、第二个...

动态编程基础——第 2 部分(动态编程是什么)

有两种方法可以使用动态规划来解决问题。在这篇文章中,我们将了解制表法。请参阅我的动态编程基础——第1部分了解记忆方法。记忆制表什么是动态规划?它是一种简单递归的优化技术。它大大减少了解决给定...

Lambda 函数,你真的的了解吗(lambda函数用法)

什么是lambda函数lambda函数是一个匿名函数,这意味着与其他函数不同,它们没有名称。这是一个函数,它添加两个数字,写成一个命名函数,可以按其名称调用它们:defadd(x,y):...

JavaScript 数组操作方法大全(js数组操作的常用方法有哪些)

数组操作是JavaScript中非常重要也非常常用的技巧。本文整理了常用的数组操作方法(包括ES6的map、forEach、every、some、filter、find、from、of等)...

系列专栏(六):解构赋值(解构赋值默认值)

ES6作为新一代JavaScript标准,已正式与广大前端开发者见面。为了让大家对ES6的诸多新特性有更深入的了解,MozillaWeb开发者博客推出了《ES6InDepth》系列文章。CSDN...

js列表遍历方法解读(js遍历链表)

JavaScript提供了多种遍历数组(或列表)的方法。以下是一些常用的方法及其解读:for循环:vararray=[1,2,3,4,5];for(vari=0;...