为什么说数组是 JavaScript 开发者必须精通的数据结构?

当被问及 "数据结构有哪些" 时,若只罗列 "数组、链表、栈、队列、树",难免显得单薄且缺乏逻辑。其实,数据结构可清晰划分为两大核心类别 ------线性结构与非线性结构,各类结构的设计逻辑和应用场景各有侧重,理解其本质能让我们更灵活地运用。​

线性结构是数据按 "一对一" 顺序排列的结构,日常开发中最为常用,核心成员包括数组、链表、栈和队列。其中,数组堪称 "万能基础款",凭借连续的内存空间实现高效随机访问,操作简单、性能稳定,是各类场景的首选;而链表虽不及数组普及,却以离散的内存分配打破了空间连续性限制,能灵活应对动态增删场景,完美弥补了数组的短板。再看栈与队列,二者虽均基于线性逻辑,但遵循截然不同的操作规则:栈是 "先进后出(FILO)" 的 "存取容器",常见于函数调用、表达式求值等场景;队列则是 "先进先出(FIFO)" 的 "排队模型",广泛应用于任务调度、消息队列等需求中。​

非线性结构则是数据呈 "一对多" 或 "多对多" 关联的结构,其中树结构最为核心,尤其以二叉树为考察重点 ------ 无论是算法面试还是实际开发中的搜索、排序场景,二叉树及其衍生结构(如二叉搜索树、红黑树)都占据重要地位。​

接下来,我们将聚焦线性结构中的 "核心成员"------ 数组,详细拆解它的底层原理、使用场景与实战技巧。

新建数组

html 复制代码
<script>
const arr = (new Array(6)).fill(0);
console.log(arr);
const arr2 = new Array(6);
console.log(arr2);
//浏览器显示  [空 ×6]
</script>

new Array(length) 创建的数组,在没有初始化之前,它的元素是 "空" 的(empty),而不是 undefined 或其他值。

遍历数组 for(i=0;i<len;i++)

我们来看这段代码:

js 复制代码
const arr = (new Array(6)).fill(0);
const len = arr.length; 
for (let i = 0;i<len;i++){
    console.log(arr[i]);
}

在循环条件中直接使用 arr.length 会有微小的性能开销。

原因如下:

在 JavaScript 中,数组是一个特殊的对象。arr.length 不是一个简单的变量,而是一个访问器属性(Accessor Property) 。这意味着,每次你访问 arr.length 时,JavaScript 引擎实际上是在调用一个隐藏的函数来获取数组的长度。

在早期的 JavaScript 引擎中,这个函数调用的开销是比较明显的。如果在一个循环中(例如执行 10000 次)每次都去调用它,累积的开销就会变得可观。

遍历数组 foreach

我们接着说 forEach,你提到的两点 ------不能 break性能相对较差------ 非常关键,我们来详细展开,并补充一些你可能忽略的细节。


1. forEach 基本用法

javascript 复制代码
const arr = [1, 2, 3];
arr.forEach((item, index, array) => {
  console.log(item, index, array);
});
  • 回调参数

    • item:当前遍历的元素(必选)
    • index:当前元素的索引(可选)
    • array:正在遍历的原数组(可选)
  • 返回值undefined(无论回调里写什么 return,都不会改变这一点)


(1)无法中途退出

forEach 没有像 for 循环那样的 breakcontinue 机制。

  • 想提前终止?做不到

    javascript 复制代码
    arr.forEach(item => {
      if (item === 2) break; // 报错:Illegal break statement
    });
  • 想跳过当前元素?用 return 模拟 continue

    javascript 复制代码
    arr.forEach(item => {
      if (item === 2) return; // 跳过当前迭代,进入下一次
      console.log(item); // 输出 1, 3
    });

map

javascript

运行

javascript 复制代码
// map
// 作用:遍历数组,并对数组中的每个元素进行指定操作(加工/转换),
//      然后将所有操作结果收集起来,返回一个全新的数组。
// 核心:不改变原数组,返回一个长度相同、值经过转换的新数组。
// 适用场景:当你需要从一个数组"派生"出另一个结构相似但值不同的数组时。

const arr = [1, 2, 3, 4, 5, 6];
const newArr = arr.map(item => item + 1); // 对每个元素加 1

console.log(arr);    // 输出: [1, 2, 3, 4, 5, 6] (原数组未改变)
console.log(newArr); // 输出: [2, 3, 4, 5, 6, 7] (新数组)

// 回调函数参数详解:
// item: 当前正在处理的数组元素 (必选)
// index: 当前元素在数组中的索引 (可选)
// array: 调用 map 方法的原数组本身 (可选)
const doubledWithIndex = arr.map((item, index) => {
    return `Index ${index}: ${item * 2}`;
});
console.log(doubledWithIndex); // 输出: ["Index 0: 2", "Index 1: 4", "Index 2: 6", ...]

// 与 forEach 的区别:
// 1. forEach 仅用于遍历,没有返回值(返回 undefined)。
// 2. map 会返回一个新数组,更适合数据转换。
// 简单说:想"生成新数组"用 map,想"单纯遍历做操作"用 forEach。

for...of

javascript

运行

javascript 复制代码
// for...of
// 作用:ES6 引入的一种新型循环语句,用于遍历可迭代对象(如 Array, Map, Set, String 等)。
// 核心:提供了一种更简洁、更具可读性的方式来遍历集合中的值。
// 优点:
//   - 语法简洁,可读性远超传统 for 循环。
//   - 避免了 for...in 循环遍历数组时可能遇到的原型链污染问题。
//   - 可以与 break, continue, return 配合使用。

const arr = [1, 2, 3, 4, 5, 6];

// 基本用法
for (let item of arr) {
    console.log(item); // 依次输出: 1, 2, 3, 4, 5, 6
}

// 如果需要索引,可以结合 Array.prototype.entries() 使用
for (let [index, item] of arr.entries()) {
    console.log(`Index ${index}: ${item}`); // 依次输出: "Index 0: 1", "Index 1: 2", ...
}

// 与传统 for 循环对比
// 传统 for 循环:
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
// for...of 写法更简洁,意图更明确。

// 与 for...in 对比 (注意:不推荐用 for...in 遍历数组)
// for...in 遍历的是键名(索引),且可能遍历到数组原型上的属性。
for (let key in arr) {
    console.log(key); // 输出: "0", "1", "2", ... (字符串形式的索引)
}

总结对比

特性 / 方法 map() for...of
核心用途 数据转换,生成新数组。 遍历迭代,访问集合中的每个值。
返回值 返回一个新数组 无返回值 (undefined)。
是否改变原数组 不改变(除非回调函数内手动修改)。 不改变(除非循环体内手动修改)。
适用对象 仅数组 (Array)。 所有可迭代对象 (Array, String, Map, Set, arguments 等)。
中断循环 无法中断(必须遍历完所有元素)。 可以使用 breakcontinue 中断或跳过。
获取索引 回调函数的第二个参数即为索引。 需要配合 arr.entries() 才能方便地获取索引。

何时使用?

  • 使用 map :当你需要将一个数组的每个元素按照某种规则进行转换,最终得到一个新的数组时。例如,从 API 获取用户列表后,提取每个用户的 idname 组成新数组。
  • 使用 for...of :当你需要遍历一个数组或其他可迭代对象,对每个元素执行一些操作(如打印、累加、根据条件进行复杂处理等),并且可能需要中途停止循环时。它是日常遍历任务中替代传统 for 循环和 forEach 的优秀选择。
相关推荐
努力努力再努力wz2 小时前
【Linux进阶系列】:线程(下)
linux·运维·服务器·c语言·数据结构·c++·算法
百***41662 小时前
Go-Gin Web 框架完整教程
前端·golang·gin
lichong9512 小时前
【macOS 版】Android studio jdk 1.8 gradle 一键打包成 release 包的脚本
android·java·前端·macos·android studio·大前端·大前端++
驯狼小羊羔2 小时前
学习随笔-http和https有何区别
前端·javascript·学习·http·https
草明2 小时前
Chrome HSTS(HTTP Strict Transport Security)
前端·chrome·http
rit84324992 小时前
瑞利信道下PSK水声通信系统均衡技术
算法
进击的野人2 小时前
JavaScript DOM操作与事件处理:从小兔鲜儿电商网站看现代前端开发实践
前端·javascript
神秘的猪头2 小时前
JavaScript 数据结构入门:从数组开始掌握核心概念
前端·javascript
倚栏听风雨2 小时前
Gemini工程的入口文件和方法是那个
前端