JavaScript 数组完全指南:从入门到实战

JavaScript 数组完全指南:从入门到实战

前言

数组是 JavaScript 中最常用的数据结构之一,也是面试中的高频考点。本文将从实际代码出发,系统讲解 JavaScript 数组的核心概念、常用方法和高级技巧,帮助你彻底掌握这一重要知识点。

一、认识数组

1.1 什么是数组

数组(Array)是一段连续的存储空间,用于存储有序的元素集合。在 JavaScript 中,数组是「开箱即用」的数据结构,无需额外引入。

javascript 复制代码
const arr = [1, 2, 3, 4, 5];
console.log(arr);  // [1, 2, 3, 4, 5]

JavaScript 的数组非常灵活:

  • 类型不限:数组元素可以是任意类型
  • 长度可变:无需预先声明固定长度
javascript 复制代码
const mixedArr = [1, 'hello', true, { name: 'Alice' }, [1, 2, 3]];

1.2 内存视角

数组的底层是连续的内存空间,通过「起始地址 + 偏移量」快速定位元素。这使得数组的随机访问效率极高,时间复杂度为 O(1)。

javascript 复制代码
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]
  • 特定操作pushpopshiftunshift

这种抽象方式让我们专注于「做什么」,而不必关心「怎么做」。

二、数组的创建方法

2.1 字面量创建

最常用、最简洁的方式:

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

2.2 构造函数创建

使用 new Array() 构造函数:

javascript 复制代码
const arr = new Array();        // 空数组
const arr2 = new Array(7);       // 指定长度为7的空数组
console.log(arr2);              // [empty × 7]

注意new Array(7) 创建的是「空位置」,不是 undefined

javascript 复制代码
const arr = new Array(7);
console.log(arr[0]);            // undefined
console.log(arr.length);        // 7

2.3 fill 方法初始化

对于需要初始值的数组,使用 fill() 方法:

javascript 复制代码
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 - 尾部添加

javascript 复制代码
const arr = ['a', 'b', 'c'];
arr.push('d');
console.log(arr);               // ['a', 'b', 'c', 'd']
console.log(arr.push('e'));     // 返回新长度: 5

3.2 pop - 尾部删除

javascript 复制代码
const arr = ['a', 'b', 'c', 'd', 'e'];
console.log(arr.pop());         // 返回被删除元素: 'e'
console.log(arr);               // ['a', 'b', 'c', 'd']

3.3 unshift - 头部添加

javascript 复制代码
const arr = [1, 2, 3];
arr.unshift(0);
console.log(arr);               // [0, 1, 2, 3]

3.4 shift - 头部删除

javascript 复制代码
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 纯函数概念

以上四个方法都会修改原数组,属于非纯函数。纯函数的特点是:

  • 不修改参数
  • 相同输入,相同输出
javascript 复制代码
// 非纯函数 - 修改原数组
function pushImpure(arr, item) {
  arr.push(item);
  return arr;
}

// 纯函数 - 不修改原数组
function pushPure(arr, item) {
  return [...arr, item];
}

四、数组遍历方法

4.1 for 循环

最传统的方式,性能最好但可读性较差:

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

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

4.2 for...of 循环

语义更好,专为可迭代对象设计:

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

for (const item of arr) {
  console.log(item);
}

4.3 forEach 方法

功能强大,但无法中断遍历 (不支持 breakcontinue):

javascript 复制代码
const arr = ['苹果', '香蕉', '橙子'];

arr.forEach((item, index, self) => {
  console.log(`${index}: ${item}`);
});

回调参数说明

参数 说明
item 当前遍历的元素
index 当前元素的索引
self 数组本身

五、高阶方法:map、filter、every、some、reduce

这些方法都基于 forEach 实现,都返回新数组 (除了 everysome 返回布尔值),都是纯函数

5.1 map - 元素转换

将数组中的每个元素映射为新值,返回全新数组:

javascript 复制代码
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 - 条件筛选

保留满足条件的元素,返回新数组:

javascript 复制代码
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 - 全量判断

检查是否所有元素都满足条件:

javascript 复制代码
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 - 存在判断

检查是否存在至少一个满足条件的元素:

javascript 复制代码
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 - 累积归约

将数组元素累积为单一值,是最强大、最灵活的方法:

javascript 复制代码
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 链式调用

多个方法可以链式使用:

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 * 10)          // [20, 40, 60, 80, 100]
  .reduce((a, b) => a + b);     // 300

console.log(result);

六、原型链与 Array.prototype

在 JavaScript 中,所有数组实例都共享 Array.prototype 上的方法。这就是原型链的体现:

javascript 复制代码
const arr = new Array();

console.log(typeof Array);           // "function" - Array 是构造函数
console.log(Array.prototype);        // 数组原型对象
console.log(Array.prototype.__proto__);  // Object.prototype

原型链结构

lua 复制代码
arr (数组实例)
  ↓ [[Prototype]]
Array.prototype (包含 push, pop, map, filter 等方法)
  ↓ [[Prototype]]
Object.prototype (所有对象的终极原型)
  ↓ [[Prototype]]
null (原型链终点)

方法来源

当你调用数组方法时:

javascript 复制代码
const arr = [1, 2, 3];
arr.push(4);  // push 方法来自 Array.prototype

七、二维数组

二维数组本质上是「数组的数组」,常用于表示矩阵、表格等结构:

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

// 访问元素
console.log(matrix[0][0]);  // 1
console.log(matrix[1][2]);  // 6

创建二维数组的坑

使用 fill 创建二维数组时要小心:

javascript 复制代码
// 错误方式
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 数组去重

javascript 复制代码
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 数组扁平化

javascript 复制代码
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 统计元素出现次数

javascript 复制代码
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 数组是前端开发中最重要的数据结构之一。本文涵盖的核心知识点:

  1. ADT 抽象数据类型:连续存储空间 + 特定操作
  2. 增删方法pushpopunshiftshift
  3. 遍历方法forfor...offorEach
  4. 高阶方法mapfiltereverysomereduce
  5. 原型链 :理解 Array.prototype 的作用
  6. 二维数组:矩阵结构与常见坑点

熟练掌握这些内容,不仅能应对面试考察,更能在实际开发中写出简洁、高效的代码。


参考资料

相关推荐
用户938515635072 小时前
深入理解 JavaScript 同步与异步:从单线程到事件循环与 Promise
前端·javascript
搬砖的码农2 小时前
造一个 Agent 运行时 #01:我决定开干,顺便把坑都写下来
前端·agent·ai编程
yingyima2 小时前
深入解析:定时任务失败重试机制的底层原理与实践
前端
哈撒Ki2 小时前
快速入门vue3与常见面试题
前端·vue.js·面试
踩着两条虫2 小时前
VTJ.PRO v2.4.2 私有化部署与升级实操指南
前端·人工智能·低代码·架构·数据挖掘
春日见2 小时前
决策规划控制面经汇总
人工智能·深度学习·算法·机器学习·自动驾驶
木斯佳2 小时前
前端八股文面经大全:美团前端暑期实习一面(2026-06-08)·面经深度解析
前端
Full Stack Developme2 小时前
Java DFA算法
java·python·算法
Uso_Magic2 小时前
VOL_实现APP多文件上传_前端多文件显示!
前端