Skip to content

JavaScript数组方法

JavaScript数组提供了丰富的内置方法,用于数组的创建、操作和转换。本文将详细介绍这些方法的使用方式和实际应用场景。

数组创建

字面量创建

javascript
// 使用数组字面量
const fruits = ["苹果", "香蕉", "橙子"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "二", true, null, {name: "张三"}];
const empty = [];

构造函数创建

javascript
// 使用Array构造函数
const fruits = new Array("苹果", "香蕉", "橙子");
const numbers = new Array(5); // 创建长度为5的空数组
const filledArray = new Array(3).fill(0); // [0, 0, 0]

其他创建方法

javascript
// Array.from - 从类数组对象或可迭代对象创建数组
const arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
const fromArrayLike = Array.from(arrayLike); // ["a", "b", "c"]

// 从字符串创建数组
const fromString = Array.from("hello"); // ["h", "e", "l", "l", "o"]

// 使用映射函数
const mapped = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]

// Array.of - 从参数创建数组
const ofNumbers = Array.of(1, 2, 3, 4); // [1, 2, 3, 4]
const ofSingle = Array.of(5); // [5],与new Array(5)不同

数组基本操作

访问元素

javascript
const fruits = ["苹果", "香蕉", "橙子"];

// 使用索引访问
console.log(fruits[0]); // "苹果"
console.log(fruits[1]); // "香蕉"
console.log(fruits[2]); // "橙子"
console.log(fruits[3]); // undefined(超出范围)

// 使用at()方法(ES2022)
console.log(fruits.at(0)); // "苹果"
console.log(fruits.at(-1)); // "橙子"(支持负索引)
console.log(fruits.at(-2)); // "香蕉"

修改元素

javascript
const fruits = ["苹果", "香蕉", "橙子"];

// 使用索引修改
fruits[1] = "葡萄";
console.log(fruits); // ["苹果", "葡萄", "橙子"]

// 添加新元素
fruits[3] = "西瓜";
console.log(fruits); // ["苹果", "葡萄", "橙子", "西瓜"]

// 稀疏数组(不推荐)
fruits[10] = "芒果";
console.log(fruits); // ["苹果", "葡萄", "橙子", "西瓜", empty × 6, "芒果"]
console.log(fruits.length); // 11

数组长度

javascript
const fruits = ["苹果", "香蕉", "橙子"];
console.log(fruits.length); // 3

// 修改长度可以截断数组
fruits.length = 2;
console.log(fruits); // ["苹果", "香蕉"]

// 增加长度会创建空槽位
fruits.length = 5;
console.log(fruits); // ["苹果", "香蕉", empty × 3]

添加和删除元素

末尾操作

javascript
const fruits = ["苹果", "香蕉"];

// push - 在末尾添加一个或多个元素,返回新长度
const newLength = fruits.push("橙子", "葡萄");
console.log(newLength); // 4
console.log(fruits); // ["苹果", "香蕉", "橙子", "葡萄"]

// pop - 移除并返回末尾元素
const lastFruit = fruits.pop();
console.log(lastFruit); // "葡萄"
console.log(fruits); // ["苹果", "香蕉", "橙子"]

开头操作

javascript
const fruits = ["香蕉", "橙子"];

// unshift - 在开头添加一个或多个元素,返回新长度
const newLength = fruits.unshift("苹果", "葡萄");
console.log(newLength); // 4
console.log(fruits); // ["苹果", "葡萄", "香蕉", "橙子"]

// shift - 移除并返回开头元素
const firstFruit = fruits.shift();
console.log(firstFruit); // "苹果"
console.log(fruits); // ["葡萄", "香蕉", "橙子"]

任意位置操作

javascript
const fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"];

// splice - 删除、替换或添加元素
// 语法: array.splice(start, deleteCount, item1, item2, ...)

// 删除元素
const removed1 = fruits.splice(1, 2); // 从索引1开始删除2个元素
console.log(removed1); // ["香蕉", "橙子"]
console.log(fruits); // ["苹果", "葡萄", "西瓜"]

// 替换元素
const removed2 = fruits.splice(1, 1, "芒果", "蓝莓");
console.log(removed2); // ["葡萄"]
console.log(fruits); // ["苹果", "芒果", "蓝莓", "西瓜"]

// 插入元素(不删除)
const removed3 = fruits.splice(2, 0, "草莓");
console.log(removed3); // [](没有删除元素)
console.log(fruits); // ["苹果", "芒果", "草莓", "蓝莓", "西瓜"]

查找元素

按值查找

javascript
const fruits = ["苹果", "香蕉", "橙子", "香蕉"];

// indexOf - 返回第一个匹配元素的索引,未找到返回-1
console.log(fruits.indexOf("香蕉")); // 1
console.log(fruits.indexOf("香蕉", 2)); // 3(从索引2开始查找)
console.log(fruits.indexOf("梨")); // -1(未找到)

// lastIndexOf - 从后向前查找,返回第一个匹配元素的索引
console.log(fruits.lastIndexOf("香蕉")); // 3
console.log(fruits.lastIndexOf("香蕉", 2)); // 1(从索引2开始向前查找)

// includes - 检查数组是否包含某个元素,返回布尔值
console.log(fruits.includes("橙子")); // true
console.log(fruits.includes("梨")); // false
console.log(fruits.includes("香蕉", 2)); // true(从索引2开始查找)

按条件查找

javascript
const people = [
  { name: "张三", age: 25 },
  { name: "李四", age: 30 },
  { name: "王五", age: 20 }
];

// find - 返回第一个满足条件的元素,未找到返回undefined
const person1 = people.find(person => person.age > 25);
console.log(person1); // { name: "李四", age: 30 }

// findIndex - 返回第一个满足条件的元素的索引,未找到返回-1
const index = people.findIndex(person => person.name === "王五");
console.log(index); // 2

// findLast - 从后向前查找,返回第一个满足条件的元素(ES2023)
const person2 = people.findLast(person => person.age > 20);
console.log(person2); // { name: "李四", age: 30 }

// findLastIndex - 从后向前查找,返回第一个满足条件的元素的索引(ES2023)
const lastIndex = people.findLastIndex(person => person.age > 20);
console.log(lastIndex); // 1

检查条件

javascript
const numbers = [1, 2, 3, 4, 5];

// every - 检查所有元素是否都满足条件
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true

const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // false

// some - 检查是否至少有一个元素满足条件
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true

const hasNegative = numbers.some(num => num < 0);
console.log(hasNegative); // false

数组转换与映射

映射

javascript
const numbers = [1, 2, 3, 4, 5];

// map - 对每个元素应用函数,返回新数组
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5](原数组不变)

// 对象数组映射
const people = [
  { name: "张三", age: 25 },
  { name: "李四", age: 30 }
];

const names = people.map(person => person.name);
console.log(names); // ["张三", "李四"]

const descriptions = people.map(person => `${person.name}今年${person.age}岁`);
console.log(descriptions); // ["张三今年25岁", "李四今年30岁"]

过滤

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

// filter - 返回满足条件的元素组成的新数组
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]

const greaterThanFive = numbers.filter(num => num > 5);
console.log(greaterThanFive); // [6, 7, 8, 9, 10]

// 过滤对象数组
const people = [
  { name: "张三", age: 25 },
  { name: "李四", age: 17 },
  { name: "王五", age: 30 },
  { name: "赵六", age: 16 }
];

const adults = people.filter(person => person.age >= 18);
console.log(adults); // [{ name: "张三", age: 25 }, { name: "王五", age: 30 }]

归约

javascript
const numbers = [1, 2, 3, 4, 5];

// reduce - 将数组归约为单个值
// 语法: array.reduce(callback(accumulator, currentValue, index, array), initialValue)

// 求和
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15

// 求乘积
const product = numbers.reduce((result, num) => result * num, 1);
console.log(product); // 120

// 找最大值
const max = numbers.reduce((max, num) => Math.max(max, num), -Infinity);
console.log(max); // 5

// 数组扁平化
const nestedArrays = [[1, 2], [3, 4], [5]];
const flattened = nestedArrays.reduce((result, arr) => result.concat(arr), []);
console.log(flattened); // [1, 2, 3, 4, 5]

// 对象数组归约
const people = [
  { name: "张三", age: 25, salary: 10000 },
  { name: "李四", age: 30, salary: 15000 },
  { name: "王五", age: 28, salary: 12000 }
];

const totalSalary = people.reduce((total, person) => total + person.salary, 0);
console.log(totalSalary); // 37000

// 按属性分组
const peopleByAge = people.reduce((groups, person) => {
  const age = person.age;
  groups[age] = groups[age] || [];
  groups[age].push(person);
  return groups;
}, {});

console.log(peopleByAge);
// {
//   25: [{ name: "张三", age: 25, salary: 10000 }],
//   30: [{ name: "李四", age: 30, salary: 15000 }],
//   28: [{ name: "王五", age: 28, salary: 12000 }]
// }

扁平化

javascript
// flat - 将嵌套数组扁平化
const nestedArrays = [1, [2, 3], [4, [5, 6]]];

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

// 指定扁平化深度
const flattened2 = nestedArrays.flat(2);
console.log(flattened2); // [1, 2, 3, 4, 5, 6]

// 完全扁平化(无限深度)
const deeplyNested = [1, [2, [3, [4, [5]]]]];
const fullyFlattened = deeplyNested.flat(Infinity);
console.log(fullyFlattened); // [1, 2, 3, 4, 5]

// flatMap - 先映射再扁平化(深度为1)
const sentences = ["Hello world", "JavaScript is fun"];
const words = sentences.flatMap(sentence => sentence.split(" "));
console.log(words); // ["Hello", "world", "JavaScript", "is", "fun"]

数组排序

基本排序

javascript
const fruits = ["香蕉", "苹果", "橙子", "葡萄"];

// sort - 对数组元素进行排序(默认按字符串顺序)
fruits.sort();
console.log(fruits); // ["橙子", "苹果", "葡萄", "香蕉"]

// 数字排序(需要比较函数)
const numbers = [40, 100, 1, 5, 25, 10];

// 错误的数字排序(按字符串顺序)
numbers.sort();
console.log(numbers); // [1, 10, 100, 25, 40, 5]

// 正确的升序排序
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 5, 10, 25, 40, 100]

// 降序排序
numbers.sort((a, b) => b - a);
console.log(numbers); // [100, 40, 25, 10, 5, 1]

对象数组排序

javascript
const people = [
  { name: "张三", age: 25 },
  { name: "李四", age: 30 },
  { name: "王五", age: 20 }
];

// 按年龄升序排序
people.sort((a, b) => a.age - b.age);
console.log(people);
// [
//   { name: "王五", age: 20 },
//   { name: "张三", age: 25 },
//   { name: "李四", age: 30 }
// ]

// 按名字字母顺序排序
people.sort((a, b) => a.name.localeCompare(b.name));
console.log(people);
// [
//   { name: "李四", age: 30 },
//   { name: "王五", age: 20 },
//   { name: "张三", age: 25 }
// ]

反转数组

javascript
const numbers = [1, 2, 3, 4, 5];

// reverse - 反转数组元素的顺序
numbers.reverse();
console.log(numbers); // [5, 4, 3, 2, 1]

数组迭代

forEach

javascript
const fruits = ["苹果", "香蕉", "橙子"];

// forEach - 对每个元素执行函数,无返回值
fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`);
});
// 输出:
// 0: 苹果
// 1: 香蕉
// 2: 橙子

// 注意:forEach无法中断循环(除非抛出异常)

其他迭代方法

javascript
const numbers = [1, 2, 3, 4, 5];

// for...of循环(推荐)
for (const num of numbers) {
  console.log(num);
}

// 传统for循环
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}

// entries(), keys(), values()
for (const [index, value] of numbers.entries()) {
  console.log(`${index}: ${value}`);
}

for (const index of numbers.keys()) {
  console.log(index);
}

for (const value of numbers.values()) {
  console.log(value);
}

数组复制与合并

复制数组

javascript
const original = [1, 2, 3];

// 使用展开运算符(浅拷贝)
const copy1 = [...original];

// 使用slice(浅拷贝)
const copy2 = original.slice();

// 使用Array.from(浅拷贝)
const copy3 = Array.from(original);

// 使用concat(浅拷贝)
const copy4 = [].concat(original);

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

合并数组

javascript
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];

// 使用展开运算符
const merged1 = [...array1, ...array2];
console.log(merged1); // [1, 2, 3, 4, 5, 6]

// 使用concat
const merged2 = array1.concat(array2);
console.log(merged2); // [1, 2, 3, 4, 5, 6]

// 合并多个数组
const array3 = [7, 8, 9];
const multiMerged = [...array1, ...array2, ...array3];
console.log(multiMerged); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

数组转换

数组与字符串转换

javascript
const fruits = ["苹果", "香蕉", "橙子"];

// join - 将数组元素连接成字符串
const joined = fruits.join(", ");
console.log(joined); // "苹果, 香蕉, 橙子"

// 不同分隔符
console.log(fruits.join("")); // "苹果香蕉橙子"
console.log(fruits.join("-")); // "苹果-香蕉-橙子"

// 字符串转数组
const str = "苹果,香蕉,橙子";
const backToArray = str.split(",");
console.log(backToArray); // ["苹果", "香蕉", "橙子"]

数组转对象

javascript
const fruits = ["苹果", "香蕉", "橙子"];

// 使用Object.assign
const obj1 = Object.assign({}, fruits);
console.log(obj1); // { 0: "苹果", 1: "香蕉", 2: "橙子" }

// 使用展开运算符
const obj2 = { ...fruits };
console.log(obj2); // { 0: "苹果", 1: "香蕉", 2: "橙子" }

// 使用Object.fromEntries(键值对数组转对象)
const entries = [["name", "张三"], ["age", 30]];
const person = Object.fromEntries(entries);
console.log(person); // { name: "张三", age: 30 }

实用技巧

数组去重

javascript
const numbers = [1, 2, 2, 3, 4, 4, 5];

// 使用Set去重
const unique1 = [...new Set(numbers)];
console.log(unique1); // [1, 2, 3, 4, 5]

// 使用filter去重
const unique2 = numbers.filter((value, index, self) => {
  return self.indexOf(value) === index;
});
console.log(unique2); // [1, 2, 3, 4, 5]

// 对象数组去重(按指定属性)
const people = [
  { id: 1, name: "张三" },
  { id: 2, name: "李四" },
  { id: 1, name: "张三" } // 重复的id
];

const uniquePeople = Array.from(
  new Map(people.map(person => [person.id, person])).values()
);
console.log(uniquePeople);
// [
//   { id: 1, name: "张三" },
//   { id: 2, name: "李四" }
// ]

数组填充

javascript
// fill - 用固定值填充数组
const filled = new Array(5).fill(0);
console.log(filled); // [0, 0, 0, 0, 0]

// 部分填充
const numbers = [1, 2, 3, 4, 5];
numbers.fill(0, 2, 4); // 从索引2到索引4(不包括4)填充0
console.log(numbers); // [1, 2, 0, 0, 5]

// 创建序列数组
const sequence = Array.from({ length: 5 }, (_, i) => i + 1);
console.log(sequence); // [1, 2, 3, 4, 5]

数组切片

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

// slice - 返回数组的一部分,不修改原数组
// 语法: array.slice(start, end),包含start,不包含end

const sliced1 = numbers.slice(2, 5);
console.log(sliced1); // [3, 4, 5]

// 省略end参数,提取到末尾
const sliced2 = numbers.slice(7);
console.log(sliced2); // [8, 9, 10]

// 使用负索引
const sliced3 = numbers.slice(-3);
console.log(sliced3); // [8, 9, 10]

const sliced4 = numbers.slice(2, -2);
console.log(sliced4); // [3, 4, 5, 6, 7, 8]

数组分块

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

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

性能考虑

高效操作

javascript
const largeArray = Array.from({ length: 1000000 }, (_, i) => i);

// 避免在循环中修改数组长度
// 不好的做法
let badPractice = [];
for (let i = 0; i < 10000; i++) {
  badPractice.push(i); // 每次都可能导致数组重新分配内存
}

// 更好的做法
let goodPractice = new Array(10000);
for (let i = 0; i < 10000; i++) {
  goodPractice[i] = i;
}

// 使用适当的迭代方法
// 如果只需要遍历,for...of通常比forEach更高效
// 如果需要索引,传统for循环通常最高效

避免常见陷阱

javascript
// 避免使用delete操作符(会留下空槽)
const arr = [1, 2, 3, 4];
delete arr[1]; // 不推荐
console.log(arr); // [1, empty, 3, 4]

// 改用splice
const arr2 = [1, 2, 3, 4];
arr2.splice(1, 1);
console.log(arr2); // [1, 3, 4]

// 避免稀疏数组
const sparse = [1, , 3]; // 有空槽的数组
console.log(sparse.length); // 3
console.log(sparse); // [1, empty, 3]

// 某些方法会跳过空槽,某些不会
sparse.forEach(item => console.log(item)); // 只输出1和3
const mapped = sparse.map(x => x * 2); // [2, empty, 6]

// 但filter会移除空槽
const filtered = sparse.filter(() => true);
console.log(filtered); // [1, 3]

总结

JavaScript数组提供了丰富的方法,使得数组操作变得简单而强大。掌握这些方法可以帮助你更有效地处理数据,编写更简洁、更高效的代码。

关键要点:

  1. 数组是有序集合,可以存储任意类型的数据
  2. 添加/删除元素的主要方法:push/popunshift/shiftsplice
  3. 查找元素的方法:indexOf/lastIndexOffind/findIndexincludes
  4. 转换数组的方法:mapfilterreduceflat/flatMap
  5. 排序和操作顺序的方法:sortreverse
  6. 迭代方法:forEachfor...of循环
  7. 数组合并与复制:展开运算符、concatslice
  8. 字符串转换:joinsplit

根据具体需求选择合适的数组方法,可以大大提高代码的可读性和性能。

用知识点燃技术的火山