JavaScript数组从入门到实战完全指南
前言
数组是 JavaScript 中最常用的数据结构之一,也是面试中的高频考点。本文将从实际代码出发,系统讲解 JavaScript 数组的核心概念、常用方法和高级技巧,帮助你彻底掌握这一重要知识点。
一、认识数组
1.1 什么是数组
数组(Array)是一段连续的存储空间,用于存储有序的元素集合。在 JavaScript 中,数组是「开箱即用」的数据结构,无需额外引入。
const arr = [1, 2, 3, 4, 5]; console.log(arr); // [1, 2, 3, 4, 5]
JavaScript 的数组非常灵活:
- 类型不限:数组元素可以是任意类型
- 长度可变:无需预先声明固定长度
const mixedArr = [1, 'hello', true, { name: 'Alice' }, [1, 2, 3]];
1.2 内存视角
数组的底层是连续的内存空间,通过「起始地址 + 偏移量」快速定位元素。这使得数组的随机访问效率极高,时间复杂度为 O(1)。
const arr = ['a', 'b', 'c', 'd', 'e']; console.log(arr[0]); // 'a' - 通过索引快速访问 console.log(arr[3]); // 'd'
1.3 ADT 抽象数据类型
在计算机科学中,我们常用 ADT(Abstract Data Type,抽象数据类型) 来描述数据结构:
连续的存储空间 + 特定的操作
以数组为例:
- 存储空间:
[1, 2, 3, 4, 5] - 特定操作:
push、pop、shift、unshift等
这种抽象方式让我们专注于「做什么」,而不必关心「怎么做」。
二、数组的创建方法
2.1 字面量创建
最常用、最简洁的方式:
const arr = [1, 2, 3, 4, 5];
2.2 构造函数创建
使用 new Array() 构造函数:
const arr = new Array(); // 空数组 const arr2 = new Array(7); // 指定长度为7的空数组 console.log(arr2); // [empty × 7]
注意:new Array(7) 创建的是「空位置」,不是 undefined:
const arr = new Array(7); console.log(arr[0]); // undefined console.log(arr.length); // 7
2.3 fill 方法初始化
对于需要初始值的数组,使用 fill() 方法:
const arr = new Array(7).fill(0); console.log(arr); // [0, 0, 0, 0, 0, 0, 0]
三、增删操作:push、pop、unshift、shift
JavaScript 数组提供了四个基本增删方法,它们都会修改原数组。
3.1 push - 尾部添加
const arr = ['a', 'b', 'c'];
arr.push('d');
console.log(arr); // ['a', 'b', 'c', 'd']
console.log(arr.push('e')); // 返回新长度: 5
3.2 pop - 尾部删除
const arr = ['a', 'b', 'c', 'd', 'e']; console.log(arr.pop()); // 返回被删除元素: 'e' console.log(arr); // ['a', 'b', 'c', 'd']
3.3 unshift - 头部添加
const arr = [1, 2, 3]; arr.unshift(0); console.log(arr); // [0, 1, 2, 3]
3.4 shift - 头部删除
const arr = [1, 2, 3, 4, 5]; console.log(arr.shift()); // 返回被删除元素: 1 console.log(arr); // [2, 3, 4, 5]
3.5 方法对比
| 方法 | 操作位置 | 返回值 | 是否修改原数组 |
|---|---|---|---|
push | 尾部添加 | 新数组长度 | ✅ |
pop | 尾部删除 | 被删除元素 | ✅ |
unshift | 头部添加 | 新数组长度 | ✅ |
shift | 头部删除 | 被删除元素 | ✅ |
3.6 纯函数概念
以上四个方法都会修改原数组,属于非纯函数。纯函数的特点是:
- 不修改参数
- 相同输入,相同输出
// 非纯函数 - 修改原数组
function pushImpure(arr, item) {
arr.push(item);
return arr;
}
// 纯函数 - 不修改原数组
function pushPure(arr, item) {
return [...arr, item];
}
四、数组遍历方法
4.1 for 循环
最传统的方式,性能最好但可读性较差:
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
4.2 for...of 循环
语义更好,专为可迭代对象设计:
const arr = [1, 2, 3, 4, 5];
for (const item of arr) {
console.log(item);
}
4.3 forEach 方法
功能强大,但无法中断遍历(不支持 break 和 continue):
const arr = ['苹果', '香蕉', '橙子'];
arr.forEach((item, index, self) => {
console.log(`${index}: ${item}`);
});
回调参数说明:
| 参数 | 说明 |
|---|---|
item | 当前遍历的元素 |
index | 当前元素的索引 |
self | 数组本身 |
五、高阶方法:map、filter、every、some、reduce
这些方法都基于 forEach 实现,都返回新数组(除了 every、some 返回布尔值),都是纯函数。
5.1 map - 元素转换
将数组中的每个元素映射为新值,返回全新数组:
const arr = [1, 2, 3, 4, 5]; // 将每个元素乘以2 const doubled = arr.map(item => item * 2); console.log(doubled); // [2, 4, 6, 8, 10] // 元素类型转换 const strings = arr.map(item => String(item)); console.log(strings); // ['1', '2', '3', '4', '5']
5.2 filter - 条件筛选
保留满足条件的元素,返回新数组:
const arr = [1, 2, 3, 4, 5]; // 筛选偶数 const evens = arr.filter(item => item % 2 === 0); console.log(evens); // [2, 4] // 筛选大于3的元素 const greaterThan3 = arr.filter(item => item > 3); console.log(greaterThan3); // [4, 5]
5.3 every - 全量判断
检查是否所有元素都满足条件:
const arr = [1, 2, 3, 4, 5]; // 检查是否全为正数 console.log(arr.every(item => item > 0)); // true // 检查是否全为偶数 console.log(arr.every(item => item % 2 === 0)); // false
特点:遇到不满足条件的元素会立即停止(短路)。
5.4 some - 存在判断
检查是否存在至少一个满足条件的元素:
const arr = [1, 2, 3, 4, 5]; // 是否存在偶数 console.log(arr.some(item => item % 2 === 0)); // true // 是否全为负数 console.log(arr.some(item => item < 0)); // false
特点:遇到满足条件的元素会立即停止(短路)。
5.5 reduce - 累积归约
将数组元素累积为单一值,是最强大、最灵活的方法:
const arr = [1, 2, 3, 4, 5]; // 求和 const sum = arr.reduce((pre, cur) => pre + cur); console.log(sum); // 15 // 求积 const product = arr.reduce((pre, cur) => pre * cur, 1); console.log(product); // 120 // 带初始值 const sumWithInit = arr.reduce((pre, cur) => pre + cur, 10); console.log(sumWithInit); // 25(10 + 1 + 2 + 3 + 4 + 5)
参数说明:
| 参数 | 说明 |
|---|---|
pre | 累积结果(初始值为第一次迭代时的 pre) |
cur | 当前元素 |
initialValue | 初始值(可选) |
5.6 方法选择指南
| 场景 | 推荐方法 |
|---|---|
| 元素转换 | map |
| 条件筛选 | filter |
| 全量判断 | every |
| 存在判断 | some |
| 累积计算 | reduce |
5.7 链式调用
多个方法可以链式使用:
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 * 10) // [20, 40, 60, 80, 100] .reduce((a, b) => a + b); // 300 console.log(result);
六、原型链与 Array.prototype
在 JavaScript 中,所有数组实例都共享 Array.prototype 上的方法。这就是原型链的体现:
const arr = new Array(); console.log(typeof Array); // "function" - Array 是构造函数 console.log(Array.prototype); // 数组原型对象 console.log(Array.prototype.__proto__); // Object.prototype
原型链结构
arr (数组实例) ↓ [[Prototype]] Array.prototype (包含 push, pop, map, filter 等方法) ↓ [[Prototype]] Object.prototype (所有对象的终极原型) ↓ [[Prototype]] null (原型链终点)
方法来源
当你调用数组方法时:
const arr = [1, 2, 3]; arr.push(4); // push 方法来自 Array.prototype
七、二维数组
二维数组本质上是「数组的数组」,常用于表示矩阵、表格等结构:
const matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; // 访问元素 console.log(matrix[0][0]); // 1 console.log(matrix[1][2]); // 6
创建二维数组的坑
使用 fill 创建二维数组时要小心:
// 错误方式
const wrong = new Array(3).fill([]);
wrong[0].push(1);
console.log(wrong); // [[1], [1], [1]] - 三个数组共享同一个引用!
// 正确方式
const correct = Array.from({ length: 3 }, () => []);
correct[0].push(1);
console.log(correct); // [[1], [], []] - 互不影响
八、综合实战
8.1 数组去重
const arr = [1, 2, 2, 3, 3, 3, 4, 5, 5]; // 方式一:Set const unique1 = [...new Set(arr)]; // 方式二:filter const unique2 = arr.filter((item, index) => arr.indexOf(item) === index); // 方式三:reduce const unique3 = arr.reduce((pre, cur) => pre.includes(cur) ? pre : [...pre, cur], []); console.log(unique1); // [1, 2, 3, 4, 5]
8.2 数组扁平化
const nested = [1, [2, [3, [4, [5]]]]];
// 方式一:flat
const flat1 = nested.flat(Infinity);
// 方式二:reduce
function flatten(arr) {
return arr.reduce((pre, cur) =>
Array.isArray(cur) ? [...pre, ...flatten(cur)] : [...pre, cur], []);
}
console.log(flatten(nested)); // [1, 2, 3, 4, 5]
8.3 统计元素出现次数
const arr = ['a', 'b', 'a', 'c', 'b', 'a'];
const count = arr.reduce((pre, cur) => {
pre[cur] = (pre[cur] || 0) + 1;
return pre;
}, {});
console.log(count); // { a: 3, b: 2, c: 1 }
九、总结
JavaScript 数组是前端开发中最重要的数据结构之一。本文涵盖的核心知识点:
- ADT 抽象数据类型:连续存储空间 + 特定操作
- 增删方法:
push、pop、unshift、shift - 遍历方法:
for、for...of、forEach - 高阶方法:
map、filter、every、some、reduce - 原型链:理解
Array.prototype的作用 - 二维数组:矩阵结构与常见坑点
熟练掌握这些内容,不仅能应对面试考察,更能在实际开发中写出简洁、高效的代码。
参考资料
到此这篇关于JavaScript数组从入门到实战完全指南的文章就介绍到这了,更多相关JS数组指南内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


最新评论