数组的创建与遍历:从入门到精通,这些坑你踩过吗? 🧐

数组是 JavaScript 中最核心的数据结构之一,几乎所有业务场景都会用到。但你真的掌握了数组的 "创建" 和 "遍历" 吗?

一、创建数组的 5 种方法:选对起点很重要

创建数组的方式看似简单,但不同方法的行为差异可能让你踩坑。

[]数组字面量

这是最常用和直接的方式,使用方括号 [] 来创建一个数组。

go 复制代码
```javascript
let arr = [1, 2, 3];
```

特点:

  • 简洁直观:是创建数组最常用的方式,几乎所有场景都能覆盖;
  • 支持稀疏数组 :允许[1, , 3]这样的写法,中间的空槽会被视为empty(但遍历可能出问题,不推荐);
  • 直接赋值:创建时可以直接指定元素,无需额外处理。

适用场景:

  • 已知初始元素的数组(如[1, 2, 3]);
  • 临时创建空数组(如const arr = [];后续动态添加元素)。

new Array()------ 参数不同,行为大不同

new Array()的行为很 "特殊",它的效果取决于传入的参数数量:

(1)传入 1 个数字参数:创建指定长度的空数组

js 复制代码
const arr=new Array(5);//指定了大小
console.log(arr);

这种数组的 "空槽"(empty)和undefined不同:

  • 空槽不会被forEachmap等方法遍历(跳过);
  • for...in遍历会忽略空槽(但for...of会遍历为undefined)。
js 复制代码
const arr2= new Array(5).fill(undefined)
arr2[8]=undefined;
console.log(arr2);
js 复制代码
for(let key in arr2){
    console.log(key,arr2[key]);
}

(2)传入多个参数:创建包含元素的数组

javascript 复制代码
const arr = new Array(1, 2, 3);
console.log(arr); // [1, 2, 3](和字面量[1,2,3]效果一致)

(3)踩坑示例:想创建长度为 5、元素为undefined的数组?

javascript 复制代码
// 错误写法:new Array(5)创建的是empty,不是undefined
const arr = new Array(5);
console.log(arr[0] === undefined); // true(访问时返回undefined)
console.log(arr.includes(undefined)); // false(因为实际是empty)

// 正确写法:用fill()填充undefined
const arr2 = new Array(5).fill(undefined);
console.log(arr2.includes(undefined)); // true(真正的undefined)

适用场景:

  • 明确需要 "指定长度的空数组"(如后续用fill填充固定值);
  • 不推荐用于创建已知元素的数组(不如字面量直观)。

Array.of()------ 参数统一视为元素

Array.of()是 ES6 新增的静态方法,专门解决new Array()的参数歧义问题:无论传入多少个参数,都被视为数组元素

javascript 复制代码
// 1. 传入1个数字:视为元素,不是长度
const arr1 = Array.of(5);
console.log(arr1); // [5](长度为1,元素是5)

// 2. 传入多个参数:和字面量效果一致
const arr2 = Array.of(1, 2, 3);
console.log(arr2); // [1, 2, 3]

// 3. 传入非数字参数:正常处理
const arr3 = Array.of('a', true, null);
console.log(arr3); // ['a', true, null]

new Array()的对比:

方法 Array.of(5) new Array(5)
结果 [5](元素为 5) [empty × 5](长度 5)
参数处理 所有参数都视为元素 单个数字参数视为长度

适用场景:

  • 动态创建数组(如参数数量不确定时,确保参数被当作元素);
  • 替代new Array(),避免因参数数量导致的歧义。

Array.from()------ 灵活转换的利器

Array.from()是 ES6 新增的静态方法,用于将类数组对象(如arguments、DOM 集合)或可迭代对象(如SetMap)转换为真正的数组 。它还支持第二个参数(类似map的回调),可以在转换时处理元素。

(1)基本用法:转换类数组

javascript 复制代码
// 类数组对象(有length和索引,但不是数组)
const likeArray = { 0: 'a', 1: 'b', length: 2 };
const arr = Array.from(likeArray);
console.log(arr); // ['a', 'b'](转为真正的数组)

(2)进阶用法:配合回调处理元素

javascript 复制代码
// 创建26个大写字母数组(A-Z)
const letters = Array.from(
  new Array(26), // 长度为26的空数组
  (_, index) => String.fromCharCode(65 + index) // 65是'A'的ASCII码
);
console.log(letters); // ['A', 'B', ..., 'Z']

(3)转换可迭代对象(如 Set)

javascript 复制代码
const set = new Set([1, 2, 3, 3]); // Set自动去重
const arr = Array.from(set);
console.log(arr); // [1, 2, 3]

特点:

  • 处理空槽Array.from(new Array(5))会将空槽转为undefined
  • 支持映射 :第二个参数可以对每个元素做处理,相当于map的简化版;
  • 真正的数组:返回的是标准数组,支持所有数组方法。

适用场景:

  • 转换类数组对象(如 DOM 集合document.querySelectorAll('div'));
  • 生成有规律的数组(如字母表、数字序列);
  • 转换可迭代对象(如SetMap)为数组。

扩展运算符...:复制或合并数组

严格来说,扩展运算符是 "数组复制 / 合并" 的工具,但也可用于创建新数组:

javascript 复制代码
// ① 复制数组
const arr = [1, 2, 3];
const copy = [...arr];

// ② 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4]

// ③ 转换可迭代对象(同Array.from())
const set = new Set([1, 2, 3]);
const arrFromSet = [...set]; // [1, 2, 3]

扩展:稀疏数组 vs 密集数组

创建数组时,一定要注意 "稀疏数组"(含空槽)和 "密集数组"(含实际元素)的区别:

类型 示例 forEach遍历 includes(undefined) 推荐度
稀疏数组 [1, , 3]new Array(3) 跳过空槽 false ❌ 不推荐
密集数组 [1, undefined, 3]new Array(3).fill(undefined) 遍历所有元素 true ✅ 推荐

记住一个原则:优先用数组字面量[],复杂场景用Array.from(),避免手动创建稀疏数组

二、遍历数组的 6 种方法:避开这些坑!

创建数组后,遍历是最常用的操作。不同遍历方式的特性差异很大,选错了可能导致逻辑错误。

1. 基础 for 循环(计数循环):性能王者

javascript 复制代码
const arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length; i++) {
  console.log(`索引${i}:`, arr[i]);
  if (arr[i] === 2) break; // 可中断循环
}

特点

  • 性能最优(直接操作索引,无额外开销);
  • 可通过break/continue控制循环;
  • 需手动维护索引(稍显繁琐)。

适用场景:对性能要求高、需要中断循环的场景。

2. forEach:简洁但无法中断

javascript 复制代码
const arr = [1, 2, 3, 4];
arr.forEach((item, index) => {
  console.log(`索引${index}:`, item);
  if (item === 2) return; // 仅跳过当前次,无法中断整个循环
});

坑点

  • 不能中断returnbreak均无效(break会报错);
  • 跳过空槽 :对稀疏数组[1, , 3],会跳过empty元素;
  • 不改变原数组 :但可通过索引修改(arr[index] = ...)。

适用场景:简单遍历,且不需要中断循环的场景。

3. for...of:迭代器遍历,兼顾优雅与灵活

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

// ① 遍历元素
for (const item of arr) {
  console.log(item);
  if (item === 2) break; // 可中断
}

// ② 同时获取索引和元素(用entries())
for (const [index, item] of arr.entries()) {
  console.log(`索引${index}:`, item);
}

entries()是数组的内置方法,返回一个迭代器对象 ,迭代结果为[索引, 元素]数组。

特点

  • 支持中断 :可使用breakcontinue
  • 遍历所有元素 :包括undefined,但对空槽(empty)视为undefined
  • 适用于所有可迭代对象 :数组、SetMap、字符串等。

适用场景:大多数需要灵活控制(中断、获取索引)的遍历场景。

4. 数组方法:map/filter/find等(遍历 + 处理)

这些方法本质上是 "遍历 + 处理" 的组合,返回新数组或值:

  • map:遍历并返回新数组(一一映射);
  • filter:遍历并返回符合条件的元素组成的新数组;
  • find:遍历并返回第一个符合条件的元素;
  • some:判断是否有至少一个元素符合条件(返回布尔值);
  • every:判断是否所有元素都符合条件(返回布尔值)。
javascript 复制代码
const arr = [1, 2, 3, 4];

// map:返回新数组
const doubled = arr.map(item => item * 2); // [2, 4, 6, 8]

// filter:筛选元素
const evens = arr.filter(item => item % 2 === 0); // [2, 4]

// find:查找第一个偶数
const firstEven = arr.find(item => item % 2 === 0); // 2

注意

  • 这些方法均不改变原数组
  • some/every外,均遍历所有元素(无法中途中断)。

5. reduce:累加器,处理复杂逻辑

reduce是最强大的数组方法之一,可将数组 "缩减" 为一个值(或对象、数组等):

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

// ① 求和
const sum = arr.reduce((prev, curr) => prev + curr, 0); // 15

// ② 求最大值
const max = arr.reduce((prev, curr) => Math.max(prev, curr), -Infinity); // 5

// ③ 分组(复杂处理)
const people = [
  { name: 'Alice', age: 20 },
  { name: 'Bob', age: 20 },
  { name: 'Charlie', age: 30 }
];
const groupedByAge = people.reduce((groups, person) => {
  const key = person.age;
  if (!groups[key]) groups[key] = [];
  groups[key].push(person);
  return groups;
}, {});
// { 20: [{name: 'Alice', ...}, {name: 'Bob', ...}], 30: [...] }

特点

  • 灵活性极高,可实现求和、分组、转换等复杂逻辑;
  • 遍历所有元素,无法中断。

适用场景:需要对数组元素进行累加、聚合、转换等复杂处理时。

6. for...in:遍历对象的 "坑王",慎用!

javascript 复制代码
const arr = [1, 2, 3];
// 给数组添加自定义属性
arr.customProp = '我是自定义属性';

// for...in会遍历所有可枚举属性(包括自定义属性和原型链属性)
for (const key in arr) {
  console.log(key); // 0, 1, 2, customProp(意外遍历到自定义属性)
}

坑点

  • 遍历所有可枚举属性:包括数组的自定义属性、原型链上的属性;
  • 索引是字符串类型key"0""1"而非数字;
  • 跳过空槽但遍历自定义属性:行为混乱。

结论永远不要用for...in遍历数组!它是为对象设计的。

相关推荐
koooo~35 分钟前
JavaScript中的Window对象
开发语言·javascript·ecmascript
hbrown1 小时前
Flask+LayUI开发手记(十一):选项集合的数据库扩展类
前端·数据库·python·layui
猫头虎1 小时前
什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景?
前端·python·scrapy·arcgis·npm·beautifulsoup·pip
迷曳1 小时前
27、鸿蒙Harmony Next开发:ArkTS并发(Promise和async/await和多线程并发TaskPool和Worker的使用)
前端·华为·多线程·harmonyos
安心不心安2 小时前
React hooks——useReducer
前端·javascript·react.js
像风一样自由20202 小时前
原生前端JavaScript/CSS与现代框架(Vue、React)的联系与区别(详细版)
前端·javascript·css
啃火龙果的兔子2 小时前
react19+nextjs+antd切换主题颜色
前端·javascript·react.js
_pengliang2 小时前
小程序按住说话
开发语言·javascript·小程序
布兰妮甜2 小时前
创建游戏或互动体验:从概念到实现的完整指南
javascript·游戏开发·游戏ai·互动体验·用户输入处理
paid槮2 小时前
HTML5如何创建容器
前端·html·html5