JavaScript 数组方法完全指南

JavaScript 数组方法完全指南

前言

数组是 JavaScript 中最常用的数据结构之一,它提供了丰富的内置方法来处理数据。掌握这些方法不仅能提高开发效率,还能让代码更加简洁优雅。本文将全面介绍 JavaScript 数组的各种方法,帮助你从入门到精通。

目录


数组基础

在 JavaScript 中,数组是一种特殊的对象,用于存储有序的数据集合。数组具有以下特点:

  • 可调整大小:数组长度可以动态变化
  • 可包含不同类型:同一个数组可以存储数字、字符串、对象等
  • 索引从 0 开始:第一个元素的索引是 0
  • 浅拷贝:数组复制操作创建的是浅拷贝
javascript 复制代码
// 数组示例
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits[0]); // 'apple'
console.log(fruits.length); // 3

创建数组

1. 字面量方式

javascript 复制代码
const arr1 = []; // 空数组
const arr2 = [1, 2, 3]; // 包含元素的数组
const arr3 = ['a', 'b', 'c', 1, 2, true]; // 混合类型

2. Array 构造函数

javascript 复制代码
const arr1 = new Array(); // 空数组
const arr2 = new Array(5); // 长度为 5 的稀疏数组
const arr3 = new Array(1, 2, 3); // [1, 2, 3]

3. Array.of()

javascript 复制代码
const arr1 = Array.of(7); // [7]
const arr2 = Array.of(1, 2, 3); // [1, 2, 3]
// 与 new Array(7) 不同,Array.of(7) 创建的是包含一个元素 7 的数组

4. Array.from()

javascript 复制代码
// 从类数组对象创建
const arr1 = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
const arr2 = Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]

// 从 Set/Map 创建
const set = new Set([1, 2, 3]);
const arr3 = Array.from(set); // [1, 2, 3]

数组方法分类

增删改查方法

push() - 在末尾添加元素
javascript 复制代码
const fruits = ['apple', 'banana'];
fruits.push('orange'); // 返回新长度 3
console.log(fruits); // ['apple', 'banana', 'orange']

// 可以一次添加多个元素
fruits.push('grape', 'mango');
console.log(fruits); // ['apple', 'banana', 'orange', 'grape', 'mango']

特点

  • 修改原数组
  • 返回数组的新长度
  • 可以添加多个元素
pop() - 移除并返回最后一个元素
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
const last = fruits.pop(); // 'orange'
console.log(fruits); // ['apple', 'banana']
console.log(last); // 'orange'

特点

  • 修改原数组
  • 返回被移除的元素
  • 如果数组为空,返回 undefined
unshift() - 在开头添加元素
javascript 复制代码
const fruits = ['banana', 'orange'];
fruits.unshift('apple'); // 返回新长度 3
console.log(fruits); // ['apple', 'banana', 'orange']

特点

  • 修改原数组
  • 返回数组的新长度
  • 性能比 push() 低(需要移动所有元素)
shift() - 移除并返回第一个元素
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
const first = fruits.shift(); // 'apple'
console.log(fruits); // ['banana', 'orange']

特点

  • 修改原数组
  • 返回被移除的元素
  • 性能比 pop()
splice() - 删除、插入或替换元素
javascript 复制代码
const fruits = ['apple', 'banana', 'orange', 'grape'];

// 删除元素:从索引 1 开始删除 2 个元素
const removed = fruits.splice(1, 2);
console.log(fruits); // ['apple', 'grape']
console.log(removed); // ['banana', 'orange']

// 插入元素:从索引 1 开始,删除 0 个,插入新元素
fruits.splice(1, 0, 'mango', 'peach');
console.log(fruits); // ['apple', 'mango', 'peach', 'grape']

// 替换元素:从索引 1 开始,删除 1 个,插入新元素
fruits.splice(1, 1, 'banana');
console.log(fruits); // ['apple', 'banana', 'peach', 'grape']

语法array.splice(start, deleteCount, ...items)

特点

  • 修改原数组
  • 返回被删除元素的数组
  • 功能强大,可以删除、插入、替换
slice() - 提取数组片段(不修改原数组)
javascript 复制代码
const fruits = ['apple', 'banana', 'orange', 'grape', 'mango'];

// 提取从索引 1 到 3(不包括 3)的元素
const sliced = fruits.slice(1, 3);
console.log(sliced); // ['banana', 'orange']
console.log(fruits); // 原数组不变

// 只提供开始索引,提取到末尾
const fromIndex2 = fruits.slice(2);
console.log(fromIndex2); // ['orange', 'grape', 'mango']

// 负数索引:从末尾开始计算
const lastTwo = fruits.slice(-2);
console.log(lastTwo); // ['grape', 'mango']

// 复制整个数组
const copy = fruits.slice();

特点

  • 不修改原数组
  • 返回新数组
  • 常用于数组复制

遍历方法

forEach() - 遍历数组
javascript 复制代码
const numbers = [1, 2, 3, 4, 5];

numbers.forEach((value, index, array) => {
  console.log(`索引 ${index}: 值 ${value}`);
});

// 输出:
// 索引 0: 值 1
// 索引 1: 值 2
// 索引 2: 值 3
// 索引 3: 值 4
// 索引 4: 值 5

// 修改原数组(不推荐,但可以)
const doubled = [];
numbers.forEach(num => {
  doubled.push(num * 2);
});
console.log(doubled); // [2, 4, 6, 8, 10]

特点

  • 不返回新数组(返回 undefined
  • 无法使用 breakcontinue(可以使用 return 跳过当前迭代)
  • 不会跳过空槽(稀疏数组)
map() - 映射数组(返回新数组)
javascript 复制代码
const numbers = [1, 2, 3, 4, 5];

// 将每个数字乘以 2
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // 原数组不变 [1, 2, 3, 4, 5]

// 提取对象属性
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 }
];
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob', 'Charlie']

特点

  • 不修改原数组
  • 返回新数组
  • 新数组长度与原数组相同
  • 最常用的数组方法之一
filter() - 过滤数组
javascript 复制代码
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 筛选偶数
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]

// 筛选对象
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 17 },
  { name: 'Charlie', age: 30 }
];
const adults = users.filter(user => user.age >= 18);
console.log(adults); // [{ name: 'Alice', age: 25 }, { name: 'Charlie', age: 30 }]

特点

  • 不修改原数组
  • 返回新数组
  • 新数组长度可能小于原数组
  • 回调函数返回 true 的元素会被保留
reduce() - 归约数组
javascript 复制代码
const numbers = [1, 2, 3, 4, 5];

// 求和
const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0);
console.log(sum); // 15

// 简化写法
const sum2 = numbers.reduce((acc, cur) => acc + cur, 0);

// 求最大值
const max = numbers.reduce((acc, cur) => Math.max(acc, cur));

// 数组转对象
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];
const userMap = users.reduce((acc, user) => {
  acc[user.id] = user.name;
  return acc;
}, {});
console.log(userMap); // { 1: 'Alice', 2: 'Bob', 3: 'Charlie' }

// 数组扁平化
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, cur) => acc.concat(cur), []);
console.log(flat); // [1, 2, 3, 4, 5, 6]

特点

  • 不修改原数组
  • 返回单个值
  • 功能强大,可以实现很多复杂操作
  • 初始值可选(建议总是提供)
reduceRight() - 从右到左归约
javascript 复制代码
const numbers = [1, 2, 3, 4];

// 从右到左计算
const result = numbers.reduceRight((acc, cur) => acc - cur);
console.log(result); // -2 (4 - 3 - 2 - 1 = -2)

// 与 reduce 对比
const result2 = numbers.reduce((acc, cur) => acc - cur);
console.log(result2); // -8 (1 - 2 - 3 - 4 = -8)

查找方法

indexOf() - 查找元素索引
javascript 复制代码
const fruits = ['apple', 'banana', 'orange', 'banana'];

const index = fruits.indexOf('banana');
console.log(index); // 1

// 从指定位置开始查找
const index2 = fruits.indexOf('banana', 2);
console.log(index2); // 3

// 找不到返回 -1
const index3 = fruits.indexOf('grape');
console.log(index3); // -1

特点

  • 使用严格相等(===)比较
  • 返回第一个匹配的索引
  • 找不到返回 -1
lastIndexOf() - 从后往前查找
javascript 复制代码
const fruits = ['apple', 'banana', 'orange', 'banana'];

const index = fruits.lastIndexOf('banana');
console.log(index); // 3
includes() - 判断是否包含元素
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

console.log(fruits.includes('banana')); // true
console.log(fruits.includes('grape')); // false

// 从指定位置开始查找
console.log(fruits.includes('apple', 1)); // false

特点

  • 返回布尔值
  • ES6 新增方法
  • indexOf() !== -1 更语义化
find() - 查找第一个满足条件的元素
javascript 复制代码
const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 17 },
  { id: 3, name: 'Charlie', age: 30 }
];

// 查找第一个年龄大于等于 18 的用户
const adult = users.find(user => user.age >= 18);
console.log(adult); // { id: 1, name: 'Alice', age: 25 }

// 找不到返回 undefined
const senior = users.find(user => user.age > 100);
console.log(senior); // undefined

特点

  • 不修改原数组
  • 返回第一个匹配的元素
  • 找不到返回 undefined
findIndex() - 查找第一个满足条件的元素索引
javascript 复制代码
const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 17 },
  { id: 3, name: 'Charlie', age: 30 }
];

const index = users.findIndex(user => user.age >= 18);
console.log(index); // 0

// 找不到返回 -1
const notFound = users.findIndex(user => user.age > 100);
console.log(notFound); // -1
findLast() - 查找最后一个满足条件的元素(ES2023)
javascript 复制代码
const numbers = [1, 2, 3, 4, 5, 6];

const lastEven = numbers.findLast(num => num % 2 === 0);
console.log(lastEven); // 6
findLastIndex() - 查找最后一个满足条件的元素索引(ES2023)
javascript 复制代码
const numbers = [1, 2, 3, 4, 5, 6];

const lastEvenIndex = numbers.findLastIndex(num => num % 2 === 0);
console.log(lastEvenIndex); // 5

转换方法

join() - 数组转字符串
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

console.log(fruits.join()); // 'apple,banana,orange'
console.log(fruits.join('')); // 'applebananaorange'
console.log(fruits.join(' - ')); // 'apple - banana - orange'

特点

  • 不修改原数组
  • 默认使用逗号分隔
  • 空数组返回空字符串
toString() - 转换为字符串
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.toString()); // 'apple,banana,orange'
// 等同于 fruits.join()
toLocaleString() - 本地化字符串
javascript 复制代码
const numbers = [1234.56, 7890.12];
console.log(numbers.toLocaleString('zh-CN')); // '1,234.56,7,890.12'
flat() - 扁平化数组
javascript 复制代码
const nested = [1, [2, 3], [4, [5, 6]]];

// 默认只扁平化一层
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]

// 指定深度
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]

// 扁平化所有层级
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6]

特点

  • 不修改原数组
  • ES2019 新增
  • 可以指定扁平化深度
flatMap() - 映射后扁平化
javascript 复制代码
const numbers = [1, 2, 3];

// 相当于 map().flat()
const result = numbers.flatMap(x => [x, x * 2]);
console.log(result); // [1, 2, 2, 4, 3, 6]

// 与 map().flat() 对比
const result2 = numbers.map(x => [x, x * 2]).flat();
console.log(result2); // [1, 2, 2, 4, 3, 6]

特点

  • 不修改原数组
  • ES2019 新增
  • 性能比 map().flat() 更好

排序和反转

sort() - 排序
javascript 复制代码
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// 默认按字符串排序(不推荐)
numbers.sort();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 6, 9]

// 数字排序(升序)
const numbers2 = [3, 1, 4, 1, 5, 9, 2, 6];
numbers2.sort((a, b) => a - b);
console.log(numbers2); // [1, 1, 2, 3, 4, 5, 6, 9]

// 数字排序(降序)
const numbers3 = [3, 1, 4, 1, 5, 9, 2, 6];
numbers3.sort((a, b) => b - a);
console.log(numbers3); // [9, 6, 5, 4, 3, 2, 1, 1]

// 对象排序
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 17 },
  { name: 'Charlie', age: 30 }
];
users.sort((a, b) => a.age - b.age);
console.log(users);
// [{ name: 'Bob', age: 17 }, { name: 'Alice', age: 25 }, { name: 'Charlie', age: 30 }]

特点

  • 修改原数组
  • 默认按字符串 Unicode 码点排序
  • 需要提供比较函数进行数字排序
reverse() - 反转数组
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
fruits.reverse();
console.log(fruits); // ['orange', 'banana', 'apple']

特点

  • 修改原数组
  • 返回反转后的数组(原数组的引用)
toSorted() - 排序(不修改原数组,ES2023)
javascript 复制代码
const numbers = [3, 1, 4, 1, 5];
const sorted = numbers.toSorted((a, b) => a - b);
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(numbers); // [3, 1, 4, 1, 5] 原数组不变
toReversed() - 反转(不修改原数组,ES2023)
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
const reversed = fruits.toReversed();
console.log(reversed); // ['orange', 'banana', 'apple']
console.log(fruits); // ['apple', 'banana', 'orange'] 原数组不变

判断方法

every() - 判断是否所有元素都满足条件
javascript 复制代码
const numbers = [2, 4, 6, 8, 10];

// 判断是否都是偶数
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // true

const numbers2 = [2, 4, 6, 7, 8];
const allEven2 = numbers2.every(num => num % 2 === 0);
console.log(allEven2); // false

特点

  • 不修改原数组
  • 返回布尔值
  • 空数组返回 true(空真值)
some() - 判断是否有元素满足条件
javascript 复制代码
const numbers = [1, 3, 5, 7, 8];

// 判断是否有偶数
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true

const numbers2 = [1, 3, 5, 7, 9];
const hasEven2 = numbers2.some(num => num % 2 === 0);
console.log(hasEven2); // false

特点

  • 不修改原数组
  • 返回布尔值
  • 空数组返回 false

归约方法

reduce() 和 reduceRight()

已在前面详细介绍,这里不再重复。


ES6+ 新方法

Array.from() - 从类数组创建数组
javascript 复制代码
// 从字符串
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']

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

// 从对象(需要 length 属性)
Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]

// 从 NodeList
const divs = document.querySelectorAll('div');
const divArray = Array.from(divs);
Array.of() - 创建数组
javascript 复制代码
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
// 与 new Array(7) 不同
fill() - 填充数组
javascript 复制代码
// 填充整个数组
const arr1 = new Array(5).fill(0);
console.log(arr1); // [0, 0, 0, 0, 0]

// 从指定位置填充
const arr2 = [1, 2, 3, 4, 5];
arr2.fill(0, 2, 4);
console.log(arr2); // [1, 2, 0, 0, 5]

特点

  • 修改原数组
  • 可以指定填充的起始和结束位置
copyWithin() - 复制数组元素
javascript 复制代码
const arr = [1, 2, 3, 4, 5];

// 将索引 0-2 的元素复制到索引 3 开始的位置
arr.copyWithin(3, 0, 3);
console.log(arr); // [1, 2, 3, 1, 2]

特点

  • 修改原数组
  • 使用场景较少
entries() - 返回键值对迭代器
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

for (const [index, value] of fruits.entries()) {
  console.log(index, value);
}
// 0 'apple'
// 1 'banana'
// 2 'orange'
keys() - 返回键迭代器
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

for (const index of fruits.keys()) {
  console.log(index);
}
// 0
// 1
// 2
values() - 返回值迭代器
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

for (const value of fruits.values()) {
  console.log(value);
}
// 'apple'
// 'banana'
// 'orange'
at() - 按索引访问(支持负数,ES2022)
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];

console.log(fruits.at(0)); // 'apple'
console.log(fruits.at(-1)); // 'orange'(最后一个)
console.log(fruits.at(-2)); // 'banana'(倒数第二个)

特点

  • 不修改原数组
  • 支持负数索引
  • fruits[fruits.length - 1] 更优雅
with() - 修改指定索引的值(不修改原数组,ES2023)
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
const newFruits = fruits.with(1, 'grape');
console.log(newFruits); // ['apple', 'grape', 'orange']
console.log(fruits); // ['apple', 'banana', 'orange'] 原数组不变
toSpliced() - 删除、插入或替换(不修改原数组,ES2023)
javascript 复制代码
const fruits = ['apple', 'banana', 'orange'];
const newFruits = fruits.toSpliced(1, 1, 'grape', 'mango');
console.log(newFruits); // ['apple', 'grape', 'mango', 'orange']
console.log(fruits); // ['apple', 'banana', 'orange'] 原数组不变

方法对比与选择

修改原数组 vs 不修改原数组

修改原数组 不修改原数组
push, pop, shift, unshift map, filter, slice
splice, sort, reverse concat, join, toString
fill, copyWithin flat, flatMap
toSorted, toReversed, with, toSpliced

选择建议

  • 优先使用不修改原数组的方法(函数式编程)
  • 需要修改原数组时,明确知道副作用

查找方法对比

方法 返回值 使用场景
indexOf 索引或 -1 简单值查找
includes 布尔值 判断是否存在
find 元素或 undefined 对象查找
findIndex 索引或 -1 对象查找索引
some 布尔值 判断是否有满足条件的元素

遍历方法对比

方法 返回值 是否可中断 使用场景
forEach undefined 简单遍历
map 新数组 转换数组
filter 新数组 过滤数组
for...of - 需要中断的遍历
reduce 单个值 归约计算

最佳实践

1. 链式调用

javascript 复制代码
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 链式调用多个方法
const result = numbers
  .filter(num => num % 2 === 0)  // [2, 4, 6, 8, 10]
  .map(num => num * 2)            // [4, 8, 12, 16, 20]
  .reduce((sum, num) => sum + num, 0); // 60

console.log(result); // 60

2. 避免在遍历中修改数组

javascript 复制代码
// ❌ 不推荐:在 forEach 中修改数组长度
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num, index) => {
  if (num % 2 === 0) {
    numbers.splice(index, 1); // 危险!会跳过元素
  }
});

// ✅ 推荐:使用 filter
const numbers2 = [1, 2, 3, 4, 5];
const odds = numbers2.filter(num => num % 2 !== 0);

3. 使用解构赋值

javascript 复制代码
// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1

// 获取第一个和剩余元素
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]

4. 性能优化

javascript 复制代码
// ❌ 不推荐:多次遍历
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0);
const doubled = evens.map(n => n * 2);
const sum = doubled.reduce((a, b) => a + b, 0);

// ✅ 推荐:单次遍历
const sum2 = numbers
  .filter(n => n % 2 === 0)
  .map(n => n * 2)
  .reduce((a, b) => a + b, 0);

// ✅ 更推荐:使用 reduce 一次完成
const sum3 = numbers.reduce((acc, n) => {
  if (n % 2 === 0) {
    return acc + n * 2;
  }
  return acc;
}, 0);

5. 处理空值和边界情况

javascript 复制代码
// 安全的数组操作
function safeArrayOperation(arr) {
  if (!Array.isArray(arr) || arr.length === 0) {
    return [];
  }
  return arr.map(item => item * 2);
}

// 使用可选链和空值合并
const result = array?.map(x => x * 2) ?? [];

6. 数组去重

javascript 复制代码
// 方法 1:使用 Set
const unique1 = [...new Set([1, 2, 2, 3, 3, 3])];
console.log(unique1); // [1, 2, 3]

// 方法 2:使用 filter + indexOf
const unique2 = [1, 2, 2, 3, 3, 3].filter((item, index, arr) => 
  arr.indexOf(item) === index
);

// 方法 3:对象数组去重
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 1, name: 'Alice' }
];
const uniqueUsers = users.filter((user, index, arr) => 
  arr.findIndex(u => u.id === user.id) === index
);
console.log(uniqueUsers); // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]

// 方法 4:使用 Map(性能更好)
const uniqueUsers2 = Array.from(
  new Map(users.map(user => [user.id, user])).values()
);

7. 数组分组

javascript 复制代码
// 使用 reduce 实现分组
const users = [
  { name: 'Alice', age: 25, city: 'Beijing' },
  { name: 'Bob', age: 30, city: 'Shanghai' },
  { name: 'Charlie', age: 25, city: 'Beijing' },
  { name: 'David', age: 30, city: 'Shanghai' }
];

// 按城市分组
const groupedByCity = users.reduce((acc, user) => {
  const city = user.city;
  if (!acc[city]) {
    acc[city] = [];
  }
  acc[city].push(user);
  return acc;
}, {});
console.log(groupedByCity);
// {
//   Beijing: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],
//   Shanghai: [{ name: 'Bob', ... }, { name: 'David', ... }]
// }

// 按年龄分组
const groupedByAge = users.reduce((acc, user) => {
  const age = user.age;
  acc[age] = acc[age] || [];
  acc[age].push(user);
  return acc;
}, {});

8. 数组分块

javascript 复制代码
// 将数组分割成指定大小的块
function chunk(array, size) {
  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(chunk(numbers, 3)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

// 使用 reduce 实现
const chunk2 = (array, size) => 
  array.reduce((acc, _, i) => {
    if (i % size === 0) {
      acc.push(array.slice(i, i + size));
    }
    return acc;
  }, []);

9. 数组合并

javascript 复制代码
// 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]
console.log(arr1); // [1, 2, 3] 原数组不变

// 使用扩展运算符(推荐)
const arr4 = [...arr1, ...arr2];
console.log(arr4); // [1, 2, 3, 4, 5, 6]

// 合并多个数组
const arr5 = [7, 8, 9];
const merged = [...arr1, ...arr2, ...arr5];
console.log(merged); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

10. 数组交集、并集、差集

javascript 复制代码
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [4, 5, 6, 7, 8];

// 交集:两个数组都有的元素
const intersection = arr1.filter(item => arr2.includes(item));
console.log(intersection); // [4, 5]

// 并集:两个数组的所有元素(去重)
const union = [...new Set([...arr1, ...arr2])];
console.log(union); // [1, 2, 3, 4, 5, 6, 7, 8]

// 差集:arr1 有但 arr2 没有的元素
const difference = arr1.filter(item => !arr2.includes(item));
console.log(difference); // [1, 2, 3]

// 对称差集:两个数组独有的元素
const symmetricDifference = [
  ...arr1.filter(item => !arr2.includes(item)),
  ...arr2.filter(item => !arr1.includes(item))
];
console.log(symmetricDifference); // [1, 2, 3, 6, 7, 8]

11. 数组随机打乱

javascript 复制代码
// Fisher-Yates 洗牌算法
function shuffle(array) {
  const arr = [...array]; // 避免修改原数组
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

const numbers = [1, 2, 3, 4, 5];
console.log(shuffle(numbers)); // 随机顺序
console.log(numbers); // [1, 2, 3, 4, 5] 原数组不变

12. 数组扁平化(多种方法)

javascript 复制代码
const nested = [1, [2, 3], [4, [5, 6]]];

// 方法 1:使用 flat()
const flat1 = nested.flat(Infinity);

// 方法 2:使用 reduce + concat
const flat2 = nested.reduce((acc, cur) => 
  acc.concat(Array.isArray(cur) ? flat2(cur) : cur), []
);

// 方法 3:使用扩展运算符(仅一层)
const flat3 = [].concat(...nested);

// 方法 4:使用 toString()(仅适用于数字)
const numbers = [[1, 2], [3, 4]];
const flat4 = numbers.toString().split(',').map(Number);

13. 数组统计

javascript 复制代码
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 求和
const sum = numbers.reduce((a, b) => a + b, 0);

// 平均值
const average = numbers.reduce((a, b) => a + b, 0) / numbers.length;

// 最大值和最小值
const max = Math.max(...numbers);
const min = Math.min(...numbers);

// 使用 reduce 求最大值和最小值
const max2 = numbers.reduce((a, b) => Math.max(a, b));
const min2 = numbers.reduce((a, b) => Math.min(a, b));

// 统计元素出现次数
const count = numbers.reduce((acc, num) => {
  acc[num] = (acc[num] || 0) + 1;
  return acc;
}, {});

14. 数组转对象

javascript 复制代码
// 键值对数组转对象
const entries = [['name', 'Alice'], ['age', 25], ['city', 'Beijing']];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: 'Alice', age: 25, city: 'Beijing' }

// 对象数组转对象(以某个属性为键)
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];
const userMap = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});
console.log(userMap);
// {
//   1: { id: 1, name: 'Alice' },
//   2: { id: 2, name: 'Bob' },
//   3: { id: 3, name: 'Charlie' }
// }

15. 数组补全方法补充

concat() - 合并数组
javascript 复制代码
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// 合并数组
const merged = arr1.concat(arr2);
console.log(merged); // [1, 2, 3, 4, 5, 6]

// 可以合并多个数组
const arr3 = [7, 8, 9];
const all = arr1.concat(arr2, arr3);
console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 也可以合并值
const withValues = arr1.concat(4, 5, [6, 7]);
console.log(withValues); // [1, 2, 3, 4, 5, 6, 7]

特点

  • 不修改原数组
  • 返回新数组
  • 可以合并多个数组或值

常见应用场景

场景 1:数据处理和转换

javascript 复制代码
// 从 API 获取数据后处理
const apiData = [
  { id: 1, name: 'Alice', status: 'active' },
  { id: 2, name: 'Bob', status: 'inactive' },
  { id: 3, name: 'Charlie', status: 'active' }
];

// 提取活跃用户的名字
const activeUsers = apiData
  .filter(user => user.status === 'active')
  .map(user => user.name);
console.log(activeUsers); // ['Alice', 'Charlie']

场景 2:表单验证

javascript 复制代码
// 验证表单字段
const formFields = [
  { name: 'username', value: 'alice', required: true },
  { name: 'email', value: '', required: true },
  { name: 'age', value: '25', required: false }
];

// 检查必填字段是否都已填写
const isValid = formFields
  .filter(field => field.required)
  .every(field => field.value.trim() !== '');

console.log(isValid); // false(email 为空)

场景 3:购物车计算

javascript 复制代码
const cart = [
  { id: 1, name: '商品A', price: 100, quantity: 2 },
  { id: 2, name: '商品B', price: 200, quantity: 1 },
  { id: 3, name: '商品C', price: 50, quantity: 3 }
];

// 计算总价
const total = cart.reduce((sum, item) => 
  sum + item.price * item.quantity, 0
);
console.log(total); // 450

// 计算商品总数
const totalQuantity = cart.reduce((sum, item) => 
  sum + item.quantity, 0
);
console.log(totalQuantity); // 6

场景 4:数据筛选和搜索

javascript 复制代码
const products = [
  { id: 1, name: 'iPhone', category: '手机', price: 5000 },
  { id: 2, name: 'iPad', category: '平板', price: 3000 },
  { id: 3, name: 'MacBook', category: '电脑', price: 10000 }
];

// 按价格筛选
const affordable = products.filter(p => p.price < 5000);
console.log(affordable); // [{ id: 2, name: 'iPad', ... }]

// 搜索功能
function searchProducts(products, keyword) {
  return products.filter(product => 
    product.name.toLowerCase().includes(keyword.toLowerCase())
  );
}

console.log(searchProducts(products, 'phone')); 
// [{ id: 1, name: 'iPhone', ... }]

场景 5:数据分组和聚合

javascript 复制代码
const orders = [
  { date: '2024-01-01', amount: 100, category: '电子产品' },
  { date: '2024-01-01', amount: 50, category: '食品' },
  { date: '2024-01-02', amount: 200, category: '电子产品' },
  { date: '2024-01-02', amount: 30, category: '食品' }
];

// 按日期分组并计算总金额
const dailyTotal = orders.reduce((acc, order) => {
  const date = order.date;
  acc[date] = (acc[date] || 0) + order.amount;
  return acc;
}, {});
console.log(dailyTotal);
// { '2024-01-01': 150, '2024-01-02': 230 }

// 按类别分组
const categoryTotal = orders.reduce((acc, order) => {
  const category = order.category;
  acc[category] = (acc[category] || 0) + order.amount;
  return acc;
}, {});
console.log(categoryTotal);
// { '电子产品': 300, '食品': 80 }

性能注意事项

1. 方法选择

javascript 复制代码
// ❌ 性能较差:多次遍历
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0);
const doubled = evens.map(n => n * 2);

// ✅ 性能较好:单次遍历
const doubled2 = numbers.reduce((acc, n) => {
  if (n % 2 === 0) {
    acc.push(n * 2);
  }
  return acc;
}, []);

2. 大数组处理

javascript 复制代码
// 对于大数组,考虑使用 for 循环
const largeArray = new Array(1000000).fill(0).map((_, i) => i);

// ❌ 可能较慢
const result1 = largeArray.map(x => x * 2);

// ✅ 可能更快
const result2 = [];
for (let i = 0; i < largeArray.length; i++) {
  result2[i] = largeArray[i] * 2;
}

3. 提前退出

javascript 复制代码
// 使用 some() 或 find() 可以提前退出
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// ✅ 找到第一个偶数就停止
const firstEven = numbers.find(n => n % 2 === 0);

// ❌ 会遍历所有元素
const firstEven2 = numbers.filter(n => n % 2 === 0)[0];

总结

JavaScript 数组提供了丰富而强大的方法,掌握这些方法可以大大提高开发效率。以下是关键要点:

核心方法分类

  1. 增删改查push, pop, shift, unshift, splice, slice
  2. 遍历转换forEach, map, filter, reduce
  3. 查找判断find, findIndex, includes, some, every
  4. 排序反转sort, reverse, toSorted, toReversed
  5. 转换方法join, flat, flatMap, concat

选择原则

  • 优先使用不修改原数组的方法(函数式编程)
  • 根据需求选择合适的方法 (查找用 find,判断用 some/every
  • 链式调用提高代码可读性
  • 注意性能,大数组考虑使用传统循环

最佳实践

  1. ✅ 使用 map 转换数组
  2. ✅ 使用 filter 过滤数组
  3. ✅ 使用 reduce 进行复杂计算
  4. ✅ 使用 find 查找元素
  5. ✅ 使用 includes 判断存在性
  6. ❌ 避免在遍历中修改数组
  7. ❌ 避免不必要的多次遍历

学习建议

  1. 理解每个方法的返回值:是否修改原数组、返回什么类型
  2. 掌握链式调用:组合使用多个方法
  3. 熟悉常见场景:去重、分组、统计等
  4. 注意边界情况:空数组、undefined、null 等
  5. 关注性能:大数组时选择合适的方法

希望这篇指南能帮助你更好地掌握 JavaScript 数组方法,在实际开发中灵活运用!


参考资源


相关推荐
社恐的下水道蟑螂2 小时前
从 JS 单线程到 Promise:彻底搞懂异步编程的 "同步化" 魔法
前端·javascript
晴殇i2 小时前
《效率翻倍!12个被90%前端忽视的CSS神技》
前端·css·面试
转角羊儿3 小时前
layui框架中,表单元素不显示问题
前端·javascript·layui
Hilaku4 小时前
当你的Ant-Design成了你最大的技术债
前端·javascript·前端框架
顾安r5 小时前
11.9 脚本网页 消消乐
前端·javascript·flask·html·pygame
宋哈哈5 小时前
页面水印sdk源码
java·前端·javascript
Kikyo--5 小时前
前端基础面试题(Css,Html,Js,Ts)
前端·javascript·css·typescript·html
火车叼位5 小时前
处理volta切换node版本之后pnpm没有识别的问题
前端·javascript
七号练习生.c5 小时前
结合Html、Javascript、Jquery做个简易的时间显示器
javascript·html·jquery