主题
回顾 流程控制语句与数组 Array(Day5 2/3)
本页对应 Day05_JavaScript,共 7 段视频,约 1 小时 5 分。
学习目标
- 能够使用索引读取和修改数组元素,并说明读取不存在元素时返回
undefined、给不存在索引赋值时会新增元素的行为。 - 能够识别稀疏数组,说明其产生原因(索引不连续、
Array构造函数指定长度、修改length变大),并能在编码中避免产生稀疏数组。 - 能够编写循环遍历数组,完成求和、求平均值、求最大值、求最小值以及将每个元素乘以 2 的操作。
- 能够使用索引结合
length、push、unshift、splice四种方式向数组添加一个或多个元素,并说明各方式添加位置的区别。 - 能够使用修改
length、pop、shift、splice四种方式删除数组元素,并说明各方式删除位置及一次删除数量的区别。
知识点
先说明材料范围
这条笔记的主题是“回顾流程控制语句”,提纲只包含循环语句(while、do while、for)和跳转语句(break、continue)。你提供的转写稿主要讲数组元素读写、稀疏数组、数组求和/最值、添加删除元素,与本条笔记不是同一主题,因此下面不把数组案例硬套进流程控制,只按笔记提纲做回顾。本节笔记没有图片和代码,所以不补图;示例代码仅用于说明语法与调试要点。
为什么需要流程控制语句
程序默认从上到下顺序执行,但真实需求里经常有两类动作:一是“重复做”,比如把一批数据逐个处理;二是“中途改变走向”,比如找到目标就停止、跳过不合格项。循环语句解决重复,跳转语句解决循环内部的提前退出或跳过。回顾时不要只背语法,要先判断:这件事是“次数确定”还是“条件满足才继续”,是“先判断”还是“至少做一次”,是“整个循环结束”还是“只跳过本轮”。
while 循环:先判断,后执行
为什么需要:当循环次数不确定、只知道“满足条件就继续”时,while 很合适。
怎么想:先写循环条件,再写循环体;循环体里必须有让条件趋向结束的变化,否则会死循环。
怎么做:
js
let i = 0;
while (i < 3) {
console.log(i);
i++;
}执行顺序是:判断 i < 3,成立才进入循环体;输出后 i++,再回到条件判断。
易错点:忘记更新 i;条件永远为真;把“循环条件”写成“退出条件”。调试时可在循环体第一行打印 i,观察是否按预期变化。
do while 循环:先执行,后判断
为什么需要:有些逻辑要求“至少执行一次”,再根据结果决定是否继续,例如先让用户输入、再判断是否继续。
怎么想:把“至少做一次”的动作放在 do 里,把继续条件放在 while 后。
怎么做:
js
let n = 0;
do {
console.log(n);
n++;
} while (n < 3);易错点:do while 末尾要写分号;它至少执行一次,即使初始条件不成立也会进入一次。若把 while 和 do while 混用,先问自己“第一次是否必须执行”。
for 循环:把初始化、条件、更新写在一起
为什么需要:次数明确、需要统一管理计数器时,for 更紧凑,读代码时三件事一眼可见。
怎么想:初始化只做一次;条件每轮开始前判断;更新在每轮循环体之后执行。
怎么做:
js
for (let i = 0; i < 3; i++) {
console.log(i);
}易错点:三个表达式用分号分隔,不是逗号;循环体内不要再随意改计数器,否则难以追踪;嵌套循环时变量名要区分。调试时可在条件旁打印当前值,确认边界是 < 还是 <=。
break:立即结束当前循环
为什么需要:找到目标后没必要继续循环,提前退出能减少无意义执行。
怎么想:break 执行后,当前这一层循环立刻结束,程序继续执行循环后面的语句。
怎么做:
js
for (let i = 0; i < 10; i++) {
if (i === 3) break;
console.log(i);
}易错点:break 只跳出它所在的那一层循环,嵌套循环中不会自动跳出外层;不要把它和函数里的 return 混淆。
continue:跳过本轮剩余,进入下一轮
为什么需要:某些数据不需要处理,但循环还要继续。
怎么想:continue 不是结束整个循环,而是跳过本次循环体后面的代码,直接进入下一次条件判断/更新。
怎么做:
js
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i);
}易错点:在 while 中使用 continue 时,如果更新语句写在 continue 后面,可能被跳过,导致死循环。把更新放在 continue 之前,或改用 for 更稳妥。
回顾时的统一判断法
先问“要不要重复”,再问“重复到什么时候”,最后问“中途要不要跳出或跳过”。while 适合条件驱动,do while 适合至少执行一次,for 适合计数驱动;break 结束当前层循环,continue 跳过本轮。流程控制的关键不是背格式,而是能画出执行顺序,并用打印语句验证边界。
一、读取与修改数组元素
为什么需要:数组用来批量保存数据,真正使用时必须能按位置取出某个元素,也能把某个位置改成新值。
怎么想:数组元素的位置叫索引,索引从 0 开始。读取写 数组名[索引];修改写 数组名[索引] = 新值。读取出来不一定只用于输出,也可以参与计算。
怎么做:
js
const arr = [100, 101, '高考证', 28, 865, 341, 200];
console.log(arr[2]); // 读取索引 2 的元素
console.log(arr[0] + arr[1]); // 前两个元素相加
console.log(arr[6]); // 读取最后一个元素
arr[2] = '新值'; // 修改索引 2 的值
arr[0] *= 2; // 先取出 arr[0],乘 2 后再赋回去易错点:读取不存在的索引不会报错,会得到 undefined,例如 arr[7];给不存在的索引赋值,会在数组中添加新元素。若索引与前面不连续,就可能产生稀疏数组。
二、稀疏数组
为什么需要:理解稀疏数组,才知道哪些写法会“占位置但没有值”,从而避免浪费空间和制造调试麻烦。
怎么想:数组里存在“只占位置、没有值”的元素,就是稀疏数组。常见来源有三种:添加元素时索引不连续;用 Array(数量) 或构造函数只传一个数字;把 length 改得比原来大。
怎么做:
js
const a = [];
a[5] = 'x'; // 中间出现空位
const b = new Array(7); // 7 个空位
const c = [1, 2, 3];
c.length = 10; // 后面补空位易错点:读取不存在元素得到 undefined;读取“存在但没有值”的元素也是 undefined。不要故意制造稀疏数组,原则是尽量避免。
三、遍历数组:求和、平均值、最大值、最小值、批量翻倍
为什么需要:数组中元素多时,不能靠眼睛看,要靠循环逐个处理。求和、平均、最大最小、统一翻倍都依赖遍历。
怎么想:求和先设 sum = 0,从索引 0 遍历到 length - 1,每次加 numbers[i];平均值就是 sum / numbers.length。最大值先假设第一个元素是最大值,再从索引 1 开始逐个比较,谁大就把 max 换成谁。最小值同理,谁小就换谁。
怎么做:
js
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
console.log(sum, sum / numbers.length);
let max = numbers[0];
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] > max) max = numbers[i];
}
let min = numbers[0];
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] < min) min = numbers[i];
}
for (let i = 0; i < numbers.length; i++) {
numbers[i] *= 2; // 等价于 numbers[i] = numbers[i] * 2
}易错点:求和时累加的是 numbers[i],不是索引 i;最大最小值从索引 1 开始比较,因为索引 0 已作为初始擂台值。批量翻倍用 *= 是简写,看不懂时可写成完整赋值。
四、添加元素:length 索引、push、unshift、splice
为什么需要:实际开发中数组长度经常变化,需要往末尾、开头、指定位置添加元素。
怎么想:末尾添加可用 arr[arr.length] = 新元素,因为 length 正好是下一个索引;push 加到末尾,可一次加多个;unshift 加到最前面;splice(索引, 0, 新元素...) 在指定位置插入,第二个参数写 0 表示不删除。
怎么做:
js
arr[arr.length] = '司马姥姥';
arr.push('令狐姥姥', '独孤姥姥');
arr.unshift('上官姥姥');
arr.splice(6, 0, '亚历山大姥姥');易错点:用索引添加时不要乱写不连续索引;splice 第二个参数写 0 才是纯添加,写 1 会删掉一个;unshift 会导致后面元素索引整体后移,内部工作量大,但开发者正常调用即可。
五、删除元素:length、pop、shift、splice
为什么需要:数组不仅要加,还要删;删除末尾、开头、指定位置和指定数量都要会。
怎么想:改 length 可删末尾若干个;pop() 删最后一个;shift() 删第一个;splice(索引, 数量) 从指定位置删指定数量。pop、shift 一次只删一个,splice 可删多个。
怎么做:
js
arr.length -= 1; // 删除最后 1 个
arr.pop(); // 删除最后一个
arr.shift(); // 删除第一个
arr.splice(2, 3); // 从索引 2 开始删除 3 个易错点:length 改小是删除,改大会补空位形成稀疏数组;pop、shift 一次只能删一个;用 splice 删除时,后面不要再写新元素,否则会变成“删除后再插入”,也就是替换效果。
六、调试提醒:控制台展开看到的是最终状态
为什么需要:初学时容易把控制台输出误解为“当时数组的快照”。
怎么想:代码执行到 console.log 时,数组当时确实可能是 5 个元素;但你在控制台点开箭头展开时,代码早已执行完,展开看到的是数组最终状态。
怎么做:需要看某一刻的状态时,可输出具体值,或输出 arr.length、JSON.stringify(arr) 等明确快照;不要只依赖展开对象。
易错点:控制台里“显示 5 个,展开却变 17 个”不是数组错了,而是调试工具的展示时机问题。理解这一点,调试数组时才不会混乱。
先厘清本节内容
本节笔记标题写作“3 函数”,但转写稿实际围绕数组的读写、遍历、稀疏数组以及增删元素展开。下面按转写稿整理,不额外扩展到函数内容。
读写数组元素:索引从 0 开始
为什么需要:数组里有很多成员,要取出某一个值或修改它,必须能精确定位。怎么想:定位靠索引,而 JavaScript 数组索引从 0 开始,所以第三个元素的索引是 2。怎么做:
js
var arr = [100, 101, 28, 865, 341, 106, 19];
console.log(arr[2]); // 读取索引2
console.log(arr[0] + arr[1]); // 读取后参与计算
arr[2] = "低大杯"; // 修改元素值
arr[6] = 250; // 修改最后一个元素
arr[0] = arr[0] * 2; // 先取原值,再乘2赋回去
console.log(arr);数组字面量也可以直接使用,不必先赋给变量,例如 [100, 200, 300][0]。易错点:读取不存在的元素不会报错,而是得到 undefined,例如 arr[7];给不存在的索引赋值会新增元素,例如 arr[7] = "上海"。如果跳着写索引,就会产生空位。
稀疏数组:占位置却没有值
为什么需要:稀疏数组会白白占内存和计算空间,实际开发中应尽量避免。怎么想:只要数组里存在“占着位置但没有值”的元素,就是稀疏数组。怎么做:常见产生方式有三种:给数组添加新元素时索引与前面不连续;用 new Array(7) 创建指定长度但无值的数组;把 length 改得比原来大。
js
var arr = [100, 101, 28, 865, 341, 106, 19];
arr[12] = 12; // 中间出现空位,长度变为13
var arr1 = new Array(7); // 全是空位
arr.length = 10; // 尾部补空位易错点:读取空位或不存在元素通常得到 undefined;不要把“空位”理解成普通字符串或某个具体值。原则是尽量避免稀疏数组。
遍历数组:求和、平均值、最值与翻倍
为什么需要:数组元素多时不能靠眼睛一个个看,要靠循环批量处理。怎么想:求和先准备 sum = 0,遍历每个元素累加;平均值就是 sum / numbers.length;最值采用“打擂台”:先假设第一个是最大/最小,再从索引 1 开始逐个比较。怎么做:
js
var numbers = [100, 101, 28, 865, 341, 106, 19];
var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
console.log(sum, sum / numbers.length);
var max = numbers[0];
for (var i = 1; i < numbers.length; i++) {
if (numbers[i] > max) max = numbers[i];
}
console.log(max);
var min = numbers[0];
for (var i = 1; i < numbers.length; i++) {
if (numbers[i] < min) min = numbers[i];
}
console.log(min);
for (var i = 0; i < numbers.length; i++) {
numbers[i] *= 2;
}易错点:求和时写 sum += i 是累加索引,不是元素;找最值时从 1 开始,因为 0 已经作为初始擂主;numbers[i] *= 2 是简写,看不懂时可写成 numbers[i] = numbers[i] * 2。
添加元素:四种常用方式
为什么需要:开发中经常要在数组尾部、头部或指定位置插入数据。怎么想:尾部追加可用 arr[arr.length] 或 push;头部插入用 unshift;指定位置插入用 splice,第二个参数写 0 表示不删除。怎么做:
js
var nameList = ["刘姥姥", "马姥姥", "黑山姥姥", "欧阳姥姥", "黑山老妖姥姥"];
nameList[nameList.length] = "司马姥姥";
nameList.push("令狐姥姥", "独孤姥姥", "西门姥姥", "东方姥姥");
nameList.unshift("上官姥姥", "爱新觉罗姥姥", "纳兰姥姥");
nameList.splice(6, 0, "亚历山大姥姥");易错点:arr[arr.length] 才是下一个新索引,不要写成 arr[arr.length - 1];splice 用于添加时第二个参数必须写 0;unshift 会改变后面元素的索引,工作量较大,但开发者直接调用即可。
删除元素:四种常用方式
为什么需要:数组也需要删尾部、删头部、删指定位置和数量。怎么想:改小 length 可删尾部;pop 删最后一个;shift 删第一个;splice(位置, 数量) 删指定位置指定数量。怎么做:
js
nameList.length -= 1; // 删除最后一个
nameList.pop(); // 删除最后一个,一次一个
nameList.shift(); // 删除第一个,一次一个
nameList.splice(2, 3); // 从索引2开始删除3个易错点:pop、shift 一次只能删一个,要删多个可多次调用;splice 删除时第二个参数是数量,不要和添加时的 0 混淆;把 length 改大不会补真实值,会产生稀疏数组。
调试提醒与小结
在控制台输出数组时,如果先输出、后修改,再展开旧输出,可能看到的是数组的“最终状态”,因为展开发生在代码执行完之后。这是调试工具的展示方式,不代表输出那一刻数组已经变了。学习数组要抓住本质:索引用中括号,读写看索引;增删优先用现成方法;避免稀疏数组。
课堂画面






代码示例
1. 读写数组元素与稀疏数组
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>读写数组元素与稀疏数组</title>
</head>
<body>
<script>
// 创建数组:数组中的成员叫元素,索引从 0 开始
var ar = [100, 101, 28, 815, 341, 106, 19];
// 读取数组元素:数组名后加中括号,中括号里写索引
console.log("ar[2] =", ar[2]);
console.log("ar[0] + ar[1] =", ar[0] + ar[1]);
// 读取不存在的元素:自动得到 undefined
console.log("ar[7] =", ar[7]);
// 给不存在的元素赋值:会在数组中添加新元素
ar[7] = "上海";
console.log("添加后的 ar =", ar);
// 修改数组中已存在的元素
ar[0] = ar[0] * 2;
console.log("修改后的 ar =", ar);
// 稀疏数组:中间跳过了索引,产生没有值的空位
var sparseArr = [];
sparseArr[12] = "x";
console.log("sparseArr.length =", sparseArr.length);
console.log("sparseArr =", sparseArr);
// new Array(7):创建指定长度的数组,元素都是空位
var emptyArr = new Array(7);
console.log("emptyArr.length =", emptyArr.length);
console.log("emptyArr =", emptyArr);
// 修改 length 属性也会产生空位
var lenArr = [1, 2, 3];
lenArr.length = 6;
console.log("lenArr.length =", lenArr.length);
console.log("lenArr =", lenArr);
</script>
</body>
</html>要点解释:
ar[2]读取的是索引为2的元素,也就是第 3 个元素;数组索引从0开始。- 读取不存在的元素不会报错,会得到
undefined;给不存在的元素赋值,会添加新元素。 sparseArr[12] = "x"会产生稀疏数组,中间空位没有值。new Array(7)和修改length变大,都可能产生没有值的空位;实际开发中应尽量避免稀疏数组。- 调试工具中展开数组时,看到的往往是数组最终状态,不是输出那一刻的状态。
2. 数组遍历案例:求和、平均值、最大、最小、元素乘 2
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数组操作案例</title>
</head>
<body>
<script>
var numbers = [865, 101, 28, 815, 341, 106, 19];
// 1. 求数组中所有元素的和
var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
console.log("所有元素的和 =", sum);
// 2. 求平均值
var avg = sum / numbers.length;
console.log("平均值 =", avg);
// 3. 求最大值:先假设第一个元素最大,再从第二个元素开始比
var max = numbers[0];
for (var j = 1; j < numbers.length; j++) {
if (numbers[j] > max) {
max = numbers[j];
}
}
console.log("最大值 =", max);
// 4. 求最小值:思路同最大值
var min = numbers[0];
for (var k = 1; k < numbers.length; k++) {
if (numbers[k] < min) {
min = numbers[k];
}
}
console.log("最小值 =", min);
// 5. 把数组中每个元素都乘以 2
for (var m = 0; m < numbers.length; m++) {
numbers[m] *= 2;
}
console.log("每个元素乘 2 后 =", numbers);
</script>
</body>
</html>要点解释:
- 求和时
sum初始值写0,循环中写sum += numbers[i],不能写成加索引。 - 求平均值直接用
sum / numbers.length。 - 最大值、最小值都先假设第一个元素是最大/最小,循环从索引
1开始比较。 - 循环条件用
i < numbers.length,不要写成i <= numbers.length,否则会越界取到undefined。 numbers[m] *= 2是简写,完整写法是numbers[m] = numbers[m] * 2。
3. 数组添加元素与删除元素
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数组添加与删除元素</title>
</head>
<body>
<script>
var nameList = ["刘姥姥", "马姥姥", "黑山姥姥", "欧阳姥姥", "司马姥姥"];
// 方式1:使用 length 作为下一个索引添加元素,避免乱写索引造成稀疏数组
nameList[nameList.length] = "令狐姥姥";
console.log("length 添加后 =", nameList);
// 方式2:push 在数组后面添加一个或多个元素
nameList.push("独孤姥姥", "西门姥姥", "东方姥姥");
console.log("push 添加后 =", nameList);
// 方式3:unshift 在数组前面添加一个或多个元素
nameList.unshift("上官姥姥");
nameList.unshift("爱新觉罗姥姥", "纳兰姥姥");
console.log("unshift 添加后 =", nameList);
// 方式4:splice 在指定位置添加元素,第二个参数写 0 表示不删除
nameList.splice(2, 0, "亚历山大姥姥");
console.log("splice 添加后 =", nameList);
// 删除方式1:修改 length,删除后面 N 个元素
nameList.length -= 1;
console.log("length 删除后 =", nameList);
// 删除方式2:pop 删除最后一个元素,一次只能删一个
nameList.pop();
console.log("pop 删除后 =", nameList);
// 删除方式3:shift 删除第一个元素,一次只能删一个
nameList.shift();
console.log("shift 删除后 =", nameList);
// 删除方式4:splice 删除指定位置、指定数量的元素
nameList.splice(2, 3);
console.log("splice 删除后 =", nameList);
</script>
</body>
</html>要点解释:
nameList[nameList.length] = "令狐姥姥"用当前长度作为下一个索引,能避免手动数索引。push添加到数组最后,unshift添加到数组最前,都可以一次添加多个元素。splice(位置, 0, 新元素)表示在指定位置添加元素;第二个参数写0很关键。pop()删除最后一个元素,shift()删除第一个元素,二者一次只能删除一个。splice(位置, 数量)删除指定位置和指定数量;用splice删除时不要再在后面写新元素,否则会变成替换。
常见错误
现象:读取
arr[arr.length]想拿最后一个元素,结果得到undefined。
原因:数组索引从0开始,最后一个元素索引是arr.length - 1。
修法:改为arr[arr.length - 1],遍历边界统一用i < arr.length。现象:给数组跳着索引赋值后,输出出现大量空位,后续计算出现
undefined/NaN。
原因:索引不连续会产生稀疏数组。
修法:新增元素优先用arr[arr.length] = 值、push、unshift、splice,不要随意跳索引赋值。现象:循环求和、求平均值、求最大最小值时结果不对,甚至出现
NaN。
原因:循环条件写成i <= arr.length,多访问了一个不存在的元素。
修法:统一检查循环条件为i < arr.length;极值初始化用arr[0],从索引1开始比较。现象:用
delete arr[i]删除元素后,数组长度没变,原位置变成空位。
原因:delete删除的是属性,不会调整数组长度和后续索引。
修法:按需求改用pop、shift、splice,或通过修改length删除尾部元素。现象:用
splice添加元素时误删了原元素,或删除元素时变成了替换。
原因:splice第二个参数表示删除数量,添加时应为0;删除时后面不应再写新元素。
修法:添加用splice(索引, 0, 新元素...);删除用splice(索引, 数量)。现象:求最大值时数组全是负数,结果却得到
0。
原因:最大值变量初始化为0,而不是数组中的实际元素。
修法:初始化max = arr[0],从i = 1开始遍历比较;最小值同理。
练习
给定一个数字数组,用循环完成:求和、求平均值、求最大值、求最小值。要求结果由代码计算,不能直接写死。
创建一个数组,分别用四种方式添加元素:
arr[arr.length] = 值、push、unshift、splice。每次添加后输出数组长度和内容,观察新元素出现的位置。对同一个数组分别练习删除:修改
length删除尾部、pop删除最后一个、shift删除第一个、splice删除指定位置指定数量。记录每次操作后的数组和长度。人为构造一个稀疏数组,例如跳索引赋值或使用
new Array(n),遍历输出每个索引和值,标出哪些位置没有值;再用连续索引或push重写一份非稀疏版本。用
splice完成两个操作:在指定元素前插入一个新元素;删除指定位置开始的若干个元素。操作后输出数组,并检查后续元素索引是否自动调整。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 读写数组的元素 | 12:15 |
| 2 | 稀疏数组 | 07:23 |
| 3 | 数组操作案例01 | 03:12 |
| 4 | 数组操作案例02 | 13:58 |
| 5 | 数组操作案例03 | 02:00 |
| 6 | 数组添加元素 | 14:57 |
| 7 | 数组删除元素 | 11:34 |
小结
- 数组读写先看索引和边界,最后一个元素永远优先想到
length - 1。 - 新增元素要尽量保持索引连续,避免跳索引赋值制造稀疏数组。
- 遍历是数组处理的基础,求和、平均值、极值、批量修改都依赖正确的循环边界。
- 添加和删除要区分尾部、头部、指定位置三类操作,位置和数量参数不能混。
splice功能强但参数最容易错,添加时牢记第二个参数写0。- 极值问题用“第一个元素先当擂主,从第二个开始比较”的模型更稳。
- 调试工具展开数组时可能显示最终状态,不要用它反推输出那一刻的数组内容。
- 头部和中间插入/删除会影响后续索引,能用尾部操作时优先用尾部操作。