JavaScript 数组
数组是存储有序数据集合的数据结构。本章将详细介绍数组的创建和操作方法。
数组基础
创建数组
// 字面量方式(推荐)
const fruits = ["苹果", "香蕉", "橙子"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, undefined];
// 构造函数方式
const arr1 = new Array();
const arr2 = new Array(5); // 创建长度为 5 的空数组
const arr3 = new Array(1, 2, 3); // [1, 2, 3]
// Array.of(ES6)- 避免构造函数歧义
const arr4 = Array.of(5); // [5]
const arr5 = Array.of(1, 2, 3); // [1, 2, 3]
// Array.from(ES6)- 从类数组或可迭代对象创建数组
const str = "hello";
const charArray = Array.from(str); // ["h", "e", "l", "l", "o"]
const set = new Set([1, 2, 3]);
const setArray = Array.from(set); // [1, 2, 3]
// 带映射函数
const doubled = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]
访问数组元素
const fruits = ["苹果", "香蕉", "橙子"];
// 使用索引访问
console.log(fruits[0]); // 苹果
console.log(fruits[1]); // 香蕉
console.log(fruits[2]); // 橙子
// 获取数组长度
console.log(fruits.length); // 3
// 访问最后一个元素
console.log(fruits[fruits.length - 1]); // 橙子
// 越界访问
console.log(fruits[10]); // undefined
数组是引用类型
const arr1 = [1, 2, 3];
const arr2 = arr1; // 引用同一个数组
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4](arr1 也被修改了)
// 浅拷贝
const arr3 = [...arr1]; // 使用展开运算符
const arr4 = arr1.slice();
const arr5 = Array.from(arr1);
数组方法
添加和删除元素
const arr = [1, 2, 3];
// push - 在末尾添加元素(返回新长度)
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
// pop - 移除末尾元素(返回被移除的元素)
const popped = arr.pop();
console.log(popped); // 4
console.log(arr); // [1, 2, 3]
// unshift - 在开头添加元素(返回新长度)
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
// shift - 移除开头元素(返回被移除的元素)
const shifted = arr.shift();
console.log(shifted); // 0
console.log(arr); // [1, 2, 3]
// splice - 添加、删除或替换元素
const months = ["Jan", "March", "April", "June"];
// 插入元素
months.splice(1, 0, "Feb");
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
// 删除元素
months.splice(3, 1);
console.log(months); // ["Jan", "Feb", "March", "June"]
// 替换元素
months.splice(3, 1, "May");
console.log(months); // ["Jan", "Feb", "March", "May"]
遍历数组
const numbers = [1, 2, 3];
// for 循环
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
// forEach
numbers.forEach((value, index, array) => {
console.log(`索引 ${index}: ${value}`);
});
// for...of
for (const num of numbers) {
console.log(num);
}
查找元素
const fruits = ["苹果", "香蕉", "橙子", "香蕉"];
// indexOf - 返回第一个匹配元素的索引
console.log(fruits.indexOf("香蕉")); // 1
console.log(fruits.indexOf("葡萄")); // -1
// lastIndexOf - 返回最后一个匹配元素的索引
console.log(fruits.lastIndexOf("香蕉")); // 3
// includes - 检查是否包含元素(ES6)
console.log(fruits.includes("香蕉")); // true
console.log(fruits.includes("葡萄")); // false
// find - 返回第一个满足条件的元素
const numbers = [1, 5, 10, 15];
const firstBig = numbers.find(n => n > 8);
console.log(firstBig); // 10
// findIndex - 返回第一个满足条件的元素索引
const firstBigIndex = numbers.findIndex(n => n > 8);
console.log(firstBigIndex); // 2
数组转换
const numbers = [1, 2, 3, 4, 5];
// map - 转换每个元素
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter - 过滤元素
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
// reduce - 汇总元素
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15
const max = numbers.reduce((acc, n) => n > acc ? n : acc, numbers[0]);
console.log(max); // 5
// flat - 扁平化数组(ES2019)
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)); // 完全扁平化
// flatMap - 先 map 再 flat
const sentences = ["Hello world", "How are you"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words); // ["Hello", "world", "How", "are", "you"]
数组排序
const fruits = ["香蕉", "苹果", "橙子"];
// sort - 就地排序(默认按字符串Unicode码点)
fruits.sort();
console.log(fruits); // ["苹果", "橙子", "香蕉"]
// 自定义排序
const numbers = [10, 2, 30, 1];
numbers.sort((a, b) => a - b); // 升序
console.log(numbers); // [1, 2, 10, 30]
numbers.sort((a, b) => b - a); // 降序
console.log(numbers); // [30, 10, 2, 1]
// 按对象属性排序
const students = [
{ name: "张三", score: 85 },
{ name: "李四", score: 92 },
{ name: "王五", score: 78 }
];
students.sort((a, b) => b.score - a.score);
console.log(students); // 按分数降序排列
// reverse - 反转数组
numbers.reverse();
console.log(numbers); // [1, 2, 10, 30]
数组连接和切片
const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = [5, 6];
// concat - 连接数组
const combined = arr1.concat(arr2, arr3);
console.log(combined); // [1, 2, 3, 4, 5, 6]
// 展开运算符(更常用)
const spreadCombined = [...arr1, ...arr2, ...arr3];
console.log(spreadCombined); // [1, 2, 3, 4, 5, 6]
// slice - 切片(不修改原数组)
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.slice(1, 3)); // [2, 3]
console.log(numbers.slice(2)); // [3, 4, 5]
console.log(numbers.slice(-2)); // [4, 5]
console.log(numbers.slice()); // 浅拷贝整个数组
数组判断
const numbers = [1, 2, 3, 4, 5];
// some - 是否存在满足条件的元素
const hasEven = numbers.some(n => n % 2 === 0);
console.log(hasEven); // true
// every - 是否所有元素都满足条件
const allPositive = numbers.every(n => n > 0);
console.log(allPositive); // true
// Array.isArray - 判断是否为数组
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray("hello")); // false
常用数组操作
搜索和过滤
const students = [
{ name: "张三", score: 85 },
{ name: "李四", score: 92 },
{ name: "王五", score: 78 },
{ name: "赵六", score: 95 }
];
// 找出最高分学生
const topStudent = students.reduce((top, s) =>
s.score > top.score ? s : top
);
console.log(`最高分:${topStudent.name} - ${topStudent.score}`);
// 找出及格的学生
const passedStudents = students.filter(s => s.score >= 60);
console.log(passedStudents);
// 按分数排序
const sortedStudents = [...students].sort((a, b) => b.score - a.score);
console.log(sortedStudents);
// 计算平均分
const avgScore = students.reduce((sum, s) => sum + s.score, 0) / students.length;
console.log(`平均分:${avgScore}`);
去重
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 5];
// 使用 Set
const unique1 = [...new Set(numbers)];
console.log(unique1); // [1, 2, 3, 4, 5]
// 使用 filter
const unique2 = numbers.filter((item, index) => numbers.indexOf(item) === index);
console.log(unique2); // [1, 2, 3, 4, 5]
// 使用 reduce
const unique3 = numbers.reduce((acc, item) =>
acc.includes(item) ? acc : [...acc, item], []
);
console.log(unique3); // [1, 2, 3, 4, 5]
数组交集、并集、差集
const a = [1, 2, 3, 4];
const b = [3, 4, 5, 6];
// 并集
const union = [...new Set([...a, ...b])];
console.log(union); // [1, 2, 3, 4, 5, 6]
// 交集
const intersection = a.filter(item => b.includes(item));
console.log(intersection); // [3, 4]
// 差集 (a - b)
const diffAB = a.filter(item => !b.includes(item));
console.log(diffAB); // [1, 2]
// 对称差集 (a ∪ b - a ∩ b)
const symDiff = [...a.filter(item => !b.includes(item)),
...b.filter(item => !a.includes(item))];
console.log(symDiff); // [1, 2, 5, 6]
二维数组
// 创建二维数组
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// 访问元素
console.log(matrix[0][0]); // 1
console.log(matrix[1][2]); // 6
// 遍历二维数组
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(`matrix[${i}][${j}] = ${matrix[i][j]}`);
}
}
// 创建指定大小的二维数组
const rows = 3, cols = 4;
const emptyMatrix = Array.from({ length: rows }, () => Array(cols).fill(0));
console.log(emptyMatrix);
// [
// [0, 0, 0, 0],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
链式调用
const orders = [
{ id: 1, product: "手机", quantity: 2, price: 2999 },
{ id: 2, product: "耳机", quantity: 1, price: 199 },
{ id: 3, product: "充电器", quantity: 3, price: 99 },
{ id: 4, product: "手机壳", quantity: 5, price: 29 }
];
// 计算订单总金额
const total = orders
.filter(order => order.quantity >= 2) // 过滤数量>=2的订单
.map(order => order.quantity * order.price) // 计算每笔订单金额
.reduce((sum, amount) => sum + amount, 0); // 汇总
console.log(`总金额:${total}`); // 6394
小结
本章我们学习了:
- 数组的创建方法
- 访问和修改数组元素
- 添加和删除元素(push、pop、shift、unshift、splice)
- 遍历数组(for、forEach、for...of)
- 查找元素(indexOf、find、findIndex)
- 数组转换(map、filter、reduce、flat)
- 数组排序和反转
- 数组连接和切片
- 常用数组操作(去重、交集、并集、差集)
练习
- 创建一个函数,接受一个数组,返回一个新数组,只包含偶数
- 创建一个函数,计算数组的平均值
- 实现数组扁平化函数
flatten(arr) - 实现数组去重函数
unique(arr) - 实现数组排序函数(不使用原生 sort)