journey
title 你的数组与循环冒险
section 数组基础
创建数组: 5: You
访问元素: 4: You
数组方法: 5: You
section 循环精通
For 循环: 4: You
While 循环: 5: You
现代语法: 4: You
section 数据处理
数组 + 循环: 5: You
现实应用: 4: You
性能优化: 5: You
flowchart LR
A["? 数组"] --> B["创建 [ ]"]
A --> C["存储多个项目"]
A --> D["通过索引访问"]
B --> B1["const arr = []"]
B --> B2["const arr = [1,2,3]"]
C --> C1["数字"]
C --> C2["字符串"]
C --> C3["布尔值"]
C --> C4["混合类型"]
D --> D1["arr[0] = 第一个"]
D --> D2["arr[1] = 第二个"]
D --> D3["arr[2] = 第三个"]
E["? 数组索引"] --> E1["索引 0: 第一个"]
E --> E2["索引 1: 第二个"]
E --> E3["索引 2: 第三个"]
E --> E4["索引 n-1: 最后一个"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
数组索引
这里有个可能最初让你觉得不寻常的地方:数组的编号是从 0 开始的,而不是从 1 开始。这个以零为基础的索引源于计算机内存的工作方式——这是自 C 语言等早期编程语言以来的惯例。数组中的每个位置都有一个被称为索引的地址号。
索引
值
说明
0
"Chocolate"
第一个元素
1
"Strawberry"
第二个元素
2
"Vanilla"
第三个元素
3
"Pistachio"
第四个元素
4
"Rocky Road"
第五个元素
✅ 你是否对数组从零开始编号感到惊讶?在某些编程语言中,索引是从 1 开始的。这里有一段有趣的历史,你可以在 Wikipedia 上阅读。
flowchart TD
A["? 循环类型"] --> B["For 循环"]
A --> C["While 循环"]
A --> D["For...of 循环"]
A --> E["forEach 方法"]
B --> B1["已知的迭代次数"]
B --> B2["基于计数器"]
B --> B3["for(init; condition; increment)"]
C --> C1["未知的迭代次数"]
C --> C2["基于条件"]
C --> C3["while(condition)"]
D --> D1["现代 ES6+"]
D --> D2["数组迭代"]
D --> D3["for(item of array)"]
E --> E1["函数式风格"]
E --> E2["数组方法"]
E --> E3["array.forEach(callback)"]
F["⏰ 何时使用"] --> F1["For:计数,索引"]
F --> F2["While:用户输入,搜索"]
F --> F3["For...of:简单迭代"]
F --> F4["forEach:函数式编程"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
For 循环
for 循环就像设置了一个计时器——你知道任务要执行多少次。它非常有序且可预测,非常适合处理数组或需要计数的场合。
For 循环结构:
组成部分
作用
示例
初始化
设定起点
let i = 0
条件
继续执行的条件
i < 10
增量
如何更新
i++
// 从0数到9
for (let i = 0; i < 10; i++) {
console.log(`Count: ${i}`);
}
// 更实际的例子:处理分数
const testScores = [85, 92, 78, 96, 88];
for (let i = 0; i < testScores.length; i++) {
console.log(`Student ${i + 1}: ${testScores[i]}%`);
}
逐步理解这个过程:
初始化 计数器变量 i 为 0
判断 条件 i < 10,为真时进入循环体
执行 代码块
执行 循环体后,i++ 使 i 增加 1
循环结束 当条件为假(即 i 达到 10)
✅ 在浏览器控制台运行此代码。改变计数器、条件或递增表达式,会发生什么?你能让它倒计时吗?
?️ For 循环掌握检测:控制重复
评估你的 for 循环理解:
for 循环的三个部分是什么,它们分别做什么?
怎么让 for 循环倒着遍历数组?
如果忘记写增量部分(i++)会怎样?
flowchart TD
A["? 开始 For 循环"] --> B["初始化: let i = 0"]
B --> C{"条件: i < array.length?"}
C -->|true| D["执行代码块"]
D --> E["递增: i++"]
E --> C
C -->|false| F["✅ 退出循环"]
G["? 常见模式"] --> G1["for(let i=0; i<n; i++)"]
G --> G2["for(let i=n-1; i>=0; i--)"]
G --> G3["for(let i=0; i<arr.length; i+=2)"]
style A fill:#e3f2fd
style F fill:#e8f5e8
style G fill:#fff3e0
循环智慧:for 循环适合你已经知道要重复多少次的情况。它们是处理数组的最常用选择!
While 循环
while 循环相当于“持续做这件事直到……”,你不一定知道会执行多少次,但知道什么时候停止。它非常适合用户输入验证,或者在找到想要的数据前不断搜索。
While 循环特征:
在条件为真时 持续执行
需要 手动管理计数变量
在每次执行前 判断条件
风险 条件永远为真则发生死循环
// 基本计数示例
let i = 0;
while (i < 10) {
console.log(`While count: ${i}`);
i++; // 别忘了递增!
}
// 更实用的示例:处理用户输入
let userInput = "";
let attempts = 0;
const maxAttempts = 3;
while (userInput !== "quit" && attempts < maxAttempts) {
userInput = prompt(`Enter 'quit' to exit (attempt ${attempts + 1}):`);
attempts++;
}
if (attempts >= maxAttempts) {
console.log("Maximum attempts reached!");
}
解析这些例子:
在循环内 手动管理计数器变量 i
防止死循环 适当增加计数器
展示 用户输入和尝试次数限制实际用例
包含 安全机制防止无限循环
♾️ While 循环智慧检测:基于条件的重复
测试你对 while 循环的理解:
使用 while 循环时最大的风险是什么?
什么情况下你会选择用 while 循环而非 for 循环?
如何预防死循环?
flowchart LR
A["? While 与 For 对比"] --> B["While 循环"]
A --> C["For 循环"]
B --> B1["未知的迭代次数"]
B --> B2["条件驱动"]
B --> B3["用户输入,搜索"]
B --> B4["⚠️ 风险:无限循环"]
C --> C1["已知的迭代次数"]
C --> C2["计数器驱动"]
C --> C3["数组处理"]
C --> C4["✅ 安全:可预测结束"]
D["?️ 安全提示"] --> D1["始终修改条件变量"]
D --> D2["包含跳出条件"]
D --> D3["设置最大迭代次数"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#ffebee
安全第一:while 循环功能强大但需要谨慎管理条件。确保条件最终会变成假!
现代循环替代方案
JavaScript 提供了更现代的循环语法,使代码更易读且减少出错。
For...of 循环(ES6+):
const colors = ["red", "green", "blue", "yellow"];
// 现代方法 - 更简洁更安全
for (const color of colors) {
console.log(`Color: ${color}`);
}
// 与传统for循环比较
for (let i = 0; i < colors.length; i++) {
console.log(`Color: ${colors[i]}`);
}
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 经典的for循环方法
for (let i = 0; i < iceCreamFlavors.length; i++) {
console.log(`Flavor ${i + 1}: ${iceCreamFlavors[i]}`);
}
// 现代的for...of方法
for (const flavor of iceCreamFlavors) {
console.log(`Available flavor: ${flavor}`);
}
理解每种方式:
通过 数组长度属性确定循环边界
传统 for 循环 按索引访问元素
for...of 循环 直接访问元素值
保证 每个数组元素被处理一次
实用数据处理示例:
const studentGrades = [85, 92, 78, 96, 88, 73, 89];
let total = 0;
let highestGrade = studentGrades[0];
let lowestGrade = studentGrades[0];
// 用一个循环处理所有成绩
for (let i = 0; i < studentGrades.length; i++) {
const grade = studentGrades[i];
total += grade;
if (grade > highestGrade) {
highestGrade = grade;
}
if (grade < lowestGrade) {
lowestGrade = grade;
}
}
const average = total / studentGrades.length;
console.log(`Average: ${average.toFixed(1)}`);
console.log(`Highest: ${highestGrade}`);
console.log(`Lowest: ${lowestGrade}`);
代码工作原理:
初始化 总和及极值追踪变量
单次循环 高效处理每个成绩
累计 总分用于计算平均数
追踪 遍历过程中最高和最低分
统计 循环结束后计算最终结果
✅ 在浏览器控制台试着自己创建数组并用循环操作它。
flowchart TD
A["? 数组数据"] --> B["? 循环处理"]
B --> C["? 结果"]
A1["[85, 92, 78, 96, 88]"] --> A
B --> B1["计算总和"]
B --> B2["查找最小/最大值"]
B --> B3["统计条件"]
B --> B4["转换数据"]
C --> C1["平均值: 87.8"]
C --> C2["最高分: 96"]
C --> C3["及格数: 5/5"]
C --> C4["字母等级"]
D["⚡ 处理模式"] --> D1["累积(求和)"]
D --> D2["比较(最小/最大)"]
D --> D3["过滤(条件)"]
D --> D4["映射(转换)"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#f3e5f5
graph TD
A["? 数组与循环精通"] --> B["? 数组基础"]
A --> C["? 循环类型"]
A --> D["? 数据处理"]
A --> E["? 现代技巧"]
B --> B1["创建: [ ]"]
B --> B2["索引: arr[0]"]
B --> B3["方法: push, pop"]
B --> B4["属性: length"]
C --> C1["For: 已知次数"]
C --> C2["While: 条件控制"]
C --> C3["For...of: 直接访问"]
C --> C4["forEach: 函数式"]
D --> D1["统计计算"]
D --> D2["数据转换"]
D --> D3["过滤与搜索"]
D --> D4["实时处理"]
E --> E1["箭头函数"]
E --> E2["方法链"]
E --> E3["解构赋值"]
E --> E4["模板字符串"]
F["? 关键优势"] --> F1["高效数据处理"]
F --> F2["减少代码重复"]
F --> F3["可扩展解决方案"]
F --> F4["更简洁语法"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec