1. 数组的创建与基本语法
1.1 使用字面量创建数组
在 JavaScript 中,最常用的创建方式是通过 数组字面量,使用方括号 [ ] 包含初始元素。通过这种方式创建的数组具有可变长度和灵活的 元素类型,元素可以是数字、字符串、对象甚至嵌套数组。一开始就定义好元素有助于提升代码可读性和减少运行时开销。
下面的示例展示了一个混合类型的数组,包含数字、字符串和布尔值,并且可以随时扩展或修改元素。
const arr = [1, 'two', true, { key: 'value' }];
console.log(arr.length); // 4
通过字面量创建的数组也支持嵌套结构,例如 二维数组,这对于数据表或矩阵操作非常常见。
1.2 构造函数与 Array 的变体
除了字面量,Array 构造函数也可以创建数组,但要注意一些特殊行为,例如传入单个数字会被解释为数组的长度而不是初始元素。因此,Array(5) 会创建一个长度为 5 的空位数组,而不是包含 5 的元素的数组。
为了更直观地创建包含具体元素的数组,可以使用 Array.of 或与之对比的 Array.from,前者接收参数并返回一个包含这些参数的数组,后者则从可迭代对象或伪数组创建数组。
const a = new Array(3); // [empty × 3]
const b = Array(3).fill(0); // [0, 0, 0]
const c = Array.of(3); // [3]
const d = Array.from({ length: 3 }, (_, i) => i); // [0, 1, 2]1.3 判断与转换:从类数组到真正的数组
在 DOM 操作或函数参数中常见的是 类数组对象,如 Arguments 或 NodeList。要进行数组方法的调用,需要将它们转换成真正的数组,常用的方法包括 Array.from、扩展运算符(spread operator)等。
下面的示例演示如何将一个 NodeList 转换为数组以使用标准数组方法。我们还可以使用扩展运算符来快速解构现有数组。
const nodes = document.querySelectorAll('div');
const nodesArray = Array.from(nodes); // 或 [...nodes]
console.log(nodesArray.length);2. 常用创建方法详解
2.1 Array.from 的深度应用
Array.from 是将可迭代对象或类数组对象转成真正数组的强大工具。它还支持传入一个映射函数,用于在转换阶段对每个元素进行处理,这对于避免额外遍历非常高效。
通过传入第二个参数,你可以在创建的同时完成数据转换,例如将数字数组平方或者从字符串创建对象。
const nums = [1, 2, 3, 4];
const squares = Array.from(nums, n => n * n); // [1, 4, 9, 16]2.2 Array.of 与数组长度的区别
Array.of 总是把传入的参数作为数组的元素返回,这与 Array 构造函数在传入单个数字时的行为不同。理解它们的差异可以避免常见的坑。
这使得在某些 API 的参数处理、记忆化数据结构的初始化时,能更精确地控制初始内容。
Array.of(7); // [7]
Array(7); // 7 个空位的数组,未赋值3. 数组遍历与变换
3.1 传统遍历与高效迭代
遍历是日常开发中的高频操作。除了经典的 for 循环,for...of 提供更简洁的语法,而 forEach 则适合在回调中执行副作用操作。需要注意的是,forEach 不能使用 break 退出循环。
在大数据量场景下,使用简单的计数型 for 循环通常会带来更好的性能,但在代码可读性方面,for...of 与 forEach 更具表达性。
const arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length; i++) {console.log(arr[i]);
}
for (const v of arr) {console.log(v);
}
arr.forEach(v => console.log(v));3.2 映射、筛选、折叠:map、filter、reduce
数组的“变换”核心在于 map、filter、reduce 三大方法。map 会返回一个新数组,元素为对原始元素应用的映射结果;filter 根据谓词返回布尔值,筛选出符合条件的元素;reduce 将数组归约为单个值,常用于求和、统计、组合数据。
组合使用这三者可以高效实现数据管道式处理,避免中间变量的过多创建,从而提升性能与可维护性。
const numbers = [1, 2, 3, 4, 5];
const evensSquared = numbers.filter(n => n % 2 === 0).map(n => n * n); // [4, 16]
const sum = numbers.reduce((acc, cur) => acc + cur, 0); // 154. 高级技巧
4.1 不可变数组与状态管理
在前端工程中,不可变数据结构 能提高可预测性和可追踪性,尤其是与状态管理库(如 Redux)配合使用时。对数组进行不变变换通常意味着返回一个新数组而不修改原始数组。
常用策略包括使用 slice、concat、以及展开运算符来创建新的变体,而不是直接修改已有元素。
const a = [1, 2, 3];
const b = a.concat(4); // [1,2,3,4]
const c = [...a, 4]; // [1,2,3,4]
console.log(a); // [1,2,3] 未被修改4.2 数组扁平化和扁平化深度控制
多维数组在现实数据中很常见,flat 与 flatMap 提供了灵活的扁平化能力。通过参数可以设定扁平的深度,便于把嵌套结构转换为一维数组。
在处理嵌套对象数组时,先扁平化再进行去重或聚合往往更高效。
const nested = [1, [2, 3], [4, [5]]];
const flatOne = nested.flat(); // [1, 2, 3, [4, [5]]]
const flatDeep = nested.flat(Infinity); // [1, 2, 3, 4, 5]
const withMapping = nested.flatMap(x => [x, x * 10]); // 根据需求展开4.3 TypedArray 与高性能数值处理
当处理大量数值数据或与 WebGL、Canvas 相关的场景时,TypedArray 提供了对二进制数据的高效操作。它们具有固定长度和更紧凑的存储结构,适合对缓冲区进行机器级操作。
注意:TypedArray 的方法与普通数组有差异,常用的有 Float32Array、Uint8Array,以及 subarray 切片等。
const bytes = new Uint8Array([10, 20, 30, 40]);
console.log(bytes.length); // 4
const sub = bytes.subarray(1, 3); // [20, 30]5. 实战案例:从入门到高阶的应用要点
5.1 将字符串按分隔符拆分并去重
现实项目中常需要将文本拆分成单词并去重,结合 split、map、reduce 等方法,可以实现高效且简洁的管道式处理。
下面的示例展示了将句子拆分为单词、清洗空白、统一大小写、再去重并排序的完整流程。
const sentence = "JavaScript 数组 创建 和 使用";
const words = sentence.toLowerCase().split(/\s+/).filter(w => w.length > 0);
const unique = Array.from(new Set(words)).sort();
console.log(unique);5.2 根据属性分组并统计出现次数
将对象数组按某个属性分组并统计出现次数,是数据处理的常见操作。通过 reduce 实现分组统计,既简洁又高效。
示例中,我们对一个包含用户对象的数组,按 role 字段分组并计数。
const users = [{ name: 'Alice', role: 'admin' },{ name: 'Bob', role: 'user' },{ name: 'Carol', role: 'user' }
];
const Groups = users.reduce((acc, u) => {acc[u.role] = (acc[u.role] || 0) + 1;return acc;
}, {}); // { admin: 1, user: 2 }5.3 高效去重与排序的组合技巧
去重通常是对数组的常见需求,结合 Set 去重再进行排序能得到快速且简洁的实现。
注意:若要处理对象去重,需要自定义比较逻辑或使用唯一标识符来避免误判。
const list = [3, 1, 2, 3, 2, 4];
const uniqueSorted = Array.from(new Set(list)).sort((a, b) => a - b);
console.log(uniqueSorted); // [1, 2, 3, 4] 

