Skip to content

A32. 数组 流程控制

2.1 🌟 数组的创建

Python 里用 numbers = [1,2,3] 创建列表,这和 JavaScript 的方式也十分相似。

JavaScript 中的数组主要有三种创建方式:

2.1.1. 🌟 数组字面量

数组字面量以 [] 包裹,元素之间用英文逗号分隔。

js
// 类似 Python 的列表字面量
const numbers = [1, 2, 3]; // 基本用法
const arr1 = [1, 'hello', true]; // 支持多类型混用,但不推荐
const arr2 = [[1,2], [3,4]]; // 数组也可以在内部嵌套数组

注意空位陷阱

若无意间连续打了两个逗号,[1, , 3] 会创建一个长度为 3 的数组,中间位置为空。应避免使用逗号分隔符时的空位,因为它可能导致意料之外的行为:在遍历时该位置被跳过。

为什么用 const 定义数组?

const 表示变量不能被重新赋值(即不能将整个数组替换为新数组),但数组内容可以修改。

而我们也常常不希望数组被无意间完全替换,所以通常用 const 定义数组。

例如:arr1.push(4) 是允许的,但 arr1 = [1,2,3] 会报错。

2.1.2. ⭐ Array 构造函数

构造函数 Array 可以用来创建数组,注意所有构造函数需要通过 new 关键字来调用

js
// 无参数:创建空数组
const arr3 = new Array();

// 传入数字作为长度
const arr4 = new Array(3); // [空 × 3]
arr4.fill(0); // [0, 0, 0] | 推荐立即用 .fill() 初始化

// 传入多个参数
const arr5 = new Array(1, 2, 3); // [1, 2, 3]

潜在风险

这种传入参数的做法事实上并不被推荐。例如 new Array(x)

  • x 是数字,则创建长度为 x 的空数组;
  • x 不是数字,则创建包含 x 作为唯一元素的数组。

所以,为了避免这种潜在的错误,最好确保 x 为数字,或直接使用数组字面量 [x],或使用 .push() 一步步添加元素。(见下)

2.1.3. Array.of 方法

Array.of 方法用于创建一系列包含给定值的数组,无论这些值的类型如何。很少用。

js
const arr6 = Array.of(1, 2); // [1, 2]
const arr7 = Array.of(3); // [3]

2.1.4. 连接数组

可以使用 concat 方法将多个数组连接成一个新数组,而不改变原来的数组。

js
const a = [1, 2];
const b = [3, 4];
const c = a.concat(b); // [1, 2, 3, 4]

总结

方法常用度特点
数组字面量⭐⭐⭐⭐简洁直观,推荐使用
Array 构造函数⭐⭐需谨慎处理参数类型
Array.of极少使用

2.2. 🌟 数组的长度

数组最关键的要素是长度。在 Python 中通过 len(arr) 来获取数组长度,而在 JavaScript 中则是 arr.length

js
const arr8 = [1, 2, 3];
console.log(arr8.length); // 3

// ❌ 最好不要像下面这样修改长度,容易出错
arr8.length = 5; // 自动填充“空”到第5位
console.log(arr8); // [1, 2, 3, 空 × 2]

TIP

长度与索引关系arr.length 总是比最大索引大 1(索引从 0 开始)。

2.3. 🌟 数组元素的增删改查

和 Python 类似,数组元素的增删改查都有对应的方法。不过,JavaScript 有一个最厉害的函数:splice

2.3.1. 🌟 在首尾添加元素

js
const arr9 = [1, 2];
arr9.push(3); // 返回新长度 3 → [1, 2, 3]
arr9.unshift(0); // 返回新长度 4 → [0, 1, 2, 3]

2.3.2. 🌟 删除首尾元素

js
const arr10 = [0, 1, 2, 3];
arr10.pop(); // 返回被删除的元素 3
arr10.shift(); // 返回被删除的元素 0

2.3.3. 🌟 修改单个元素

注意索引从 0 开始

js
const arr11 = [10, 20, 30];
arr11[1] = 25; // 修改了第 2 个元素 → [10, 25, 30]

2.3.4. 🌟 查询元素

js
const arr12 = [10, 20, 30, 20];

// 返回子数组(索引左开右闭)
arr12.slice(1, 3); // 第 [1,3) 个索引,[20, 30]

// 查找第一个索引(-1 表示不存在)
arr12.indexOf(20); // 1
arr12.indexOf(40); // -1

2.3.5. ⭐ 任意位置的插入和删除

js
const arr13 = [1, 2, 3, 4];

// 删除 2 个元素,插入新元素
arr13.splice(1, 2, 'a', 'b'); // 返回 [2, 3]
// 新数组 → [1, 'a', 'b', 4]

闭包传参

splice 中插入多个元素时,应通过 逗号分隔的多个参数 传递(如 'a', 'b'),而不是直接传入一个数组。
若直接传入数组(如 [1,2]),splice 会将其视为 单个元素 插入,而非展开多个值。 示例:

js
const arr = [1, 2];
const values = [3, 4];
arr.splice(2, 0, values); // ❌ 插入整个数组作为单个元素 → [1, 2, [3,4]]
arr.splice(2, 0, 3, 4); // ✅ 插入多个参数 → [1, 2, 3, 4]
arr.splice(2, 0, ...values); // ✅ 使用 ... 展开数组,插入展开的元素 → [1, 2, 3, 4]

2.3.6. ⭐ splice 方法的常见技巧

1. 删除元素

js
arr13.splice(index, count); // 删除 index 开始的 count 个元素

2. 插入元素

js
arr13.splice(index, 0, ...items); // 删除 0 个元素,即忽略删除步骤;只从 index 插入 items

3. 替换元素

js
arr13.splice(index, count, ...items); // 删除 count 个,替换为 items

2.3.7 数组方法总结

方法名作用参数返回值示例
push尾部添加...items新长度[1].push(2) → 2
pop删除末尾元素被删元素[1,2].pop() → 2
unshift头部添加...items新长度[2].unshift(1) → 2
shift删除首元素被删元素[1,2].shift() → 1
slice截取子数组start, end新数组[1,2,3].slice(1) → [2,3]
splice删除/插入元素index, count, ...items被删元素数组[1,2].splice(1, 0, 3) → []
indexOf查找索引searchElement索引或 -1[1,2].indexOf(2) → 1

2.4 🌟 if 关键字及其分支结构

2.4.1. 🌟 基础 if 结构

js
if (confirm("确认执行?")) {
  alert("已确认!");
}

真假值

if 中,表达式会被自动转换为布尔值,转换为 true 才运行内部语句。

JavaScript 中 0""nullundefinedNaN 都为假值。

所以,if (0) 不会运行,但 if ("1") 会运行。

2.4.2. 🌟 if...else 结构

js
if (age >= 18) {
  console.log("成年人");
} else {
  console.log("未成年人");
}

与 Python 的区别

  • 条件必须用括号包裹,后面必须跟大括号 {}
  • 单行省略大括号:
    js
    if (a === 1) console.log("Hello");
    但这种方式容易引发错误(比如加代码后,本来要加入内部的代码行被判定为外部)。

2.4.3. 🌟 多重条件判断

WARNING

在 Python 中使用 elif,但在 JavaScript 中使用 else if

js
if (score >= 90) {
  console.log("A");
} else if (score >= 80) {
  console.log("B");
} else {
  console.log("C");
}

TIP

else if 与多个 if 的区别

  • else if 是互斥的,一旦满足某个条件,后续条件不再判断
  • 多个独立 if 可以同时满足多个条件
    js
    if (true) { ... }
    if (true) { ... } // 继续执行

2.5. ⭐ while 关键字及其循环结构

最常见的循环需要循环条件和循环体:什么时候继续循环?循环的时候做什么?while 循环就是最基础的循环结构。

形式为 while (condition) { code },其中 condition 是一个布尔表达式,满足时一直执行,code 是循环体,需包含对相应变量的更新。

同样地,JavaScript 中 while 循环也需要用大括号 {} 包裹,条件也需要用小括号 () 包裹。

js
let i = 0;
while (i < 3) {
  console.log(i);
  i++; // 忘记更新会导致死循环!
}

死循环问题

若循环条件变量忘记更新(如 i++),程序将无限运行直至崩溃。

2.6. 🌟 for 关键字及其循环结构

while 循环虽然具有通用的特性,但常常需要在循环开始前初始化循环变量,以及在循环体中更新循环变量,这些都很容易忘记,循环体外的变量也容易造成混淆。为此,我们有 for 循环,提炼常见循环的流程,简化开发。

2.6.1. 🌟 基础 for 循环

js
// 初始化;条件;更新
for (let i = 0; i < 3; i++) {
  console.log(i);
}

注意语法:for ( ; ; ) {},两个分号将括号内分为三部分结构:

部分说明
初始化let i = 0
条件i < 3
更新i++

WARNING

常见陷阱:

  • ❌ 索引越界:
    js
    const arr15 = [1, 2];
    for (let i = 0; i <= arr15.length; i++) { // 不应为 <=,而是 <
      console.log(arr15[i]); // 最后一次访问 arr15[2] 为 undefined
    }
  • ❌ 在循环体内修改 arr.length
    js
    const arr16 = [1, 2, 3];
    for (let i = 0; i < arr16.length; i++) {
      arr16.length = 1; // 循环提前终止
      console.log(arr16[i]);
    }
  • (不推荐)用 var 声明 i 甚至不使用 letvarconst 的任意一种:
    js
    var i = 0;
    for (var i = 0; i < 3; i++) {
      // ...
    }
    console.log(i); // 3(在外部仍然能使用该循环变量,但此时这个变量的意义已经不大)

2.6.2. 🌟 for ... of 循环

为了解决数不清楚索引的问题或代码重复性太高的问题,对于数组(或其他可迭代对象),我们可以使用 for ... of 循环。

js
const arr14 = [10, 20, 30];
for (const item of arr14) {
  console.log(item); // 直接获取元素值
}

2.6.3. ⭐ for ... in 循环

for ... of 中损失了索引信息,若需要索引信息,我们可以使用 for... in 循环。

js
const arr15 = [10, 20, 30];
for (const index in obj) {
  console.log(index); // "0", "1", "2"
  console.log(index + 1); // ❌ "01", "11", "21"
  console.log(Number(index) + 1); // ✅ 1, 2, 3
}

索引类型

for... in 循环中,key字符串类型,而不是数字类型。

这是因为 for... in 循环遍历的是对象的属性名,而许多对象的属性名无法用数字表示,所以为了兼容统一,全部返回字符串。

2.7. 🌟 break 和 continue 关键字

基础的循环结构比较死板,但有时循环到某种程度就可以“到此为止”了。比如,用枚举法求最小符合条件的整数,一旦有一个符合条件,后续就无需再枚举了,这时就需要灵活地跳出循环。

2.7.1. 🌟 break 关键字

js
for (let i = 0; i < 10; i++) {
  if (i === 5) break; // 到 5 直接打断,跳出循环
  console.log(i); // 全过程只输出了 0~4
}

2.7.2. ⭐ continue 关键字

js
for (let i = 0; i < 5; i++) {
  if (i % 2 === 0) continue; // 到偶数时终止本次迭代,继续进行下一次迭代。
  console.log(i); // 全过程输出了 1, 3
}

知识回顾

  1. 数组创建与操作

    1. 数组创建方式
      • 字面量const arr = [1,2,3](推荐)
      • 构造函数new Array()(需注意参数类型)
      • Array.ofArray.of(1, 2)(少用)
    2. 数组操作方法
      • 首尾增删push/popunshift/shift
      • 修改元素arr[index] = value
      • 查询元素slice(start, end)indexOf(searchElement)
      • 任意位置操作splice(index, count, ...items)(核心方法,先删除再插入)
    3. 数组长度特性
      • arr.length 动态可变,但不等于实际元素数(可能包含 undefined
      • 索引从 0 开始,最大索引为 length - 1
  2. 流程控制

    1. 分支结构
      • if (条件) { ... }:条件必须加括号
      • if...else:互斥分支
      • else if:多级互斥条件
      • 与 Python 的区别:不依赖缩进,必须用 {} 包裹代码块
    2. 循环结构
      • while:先判断条件,再执行循环体
      • for:三部分结构(初始化、条件、更新)
      • for...of:遍历元素值
      • for...in:遍历索引(对象属性名)
      • 常见陷阱
        • 死循环(忘记更新循环变量)
        • 索引越界(i <= arr.length
        • 修改 arr.length 导致循环异常
        • 作用域污染(用 var 声明循环变量)
        • for...in 索引类型为字符串
      • break:立即退出当前循环
      • continue:跳过当前迭代,进入下一次循环

课后练习

  1. (单选)以下代码执行后,arr17 的值是什么?

    js
    const arr17 = [1, 2, 3];
    arr17.splice(1, 0, 4);
    • A. [1, 4, 2, 3]
    • B. [4, 1, 2, 3]
    • C. [1, 2, 3, 4]
    • D. [1, 2, 4, 3]
  2. (编程)使用三种 for 循环的方式打印列表中元素的 2 倍:

    js
    const arr18 = [1, 2, 3];
    for (_____________) {
      console.log(_________________);
    }
  3. (纠错)运行这段代码后,浏览器卡死,可能是什么原因?

    js
    for (var i = 1; i <= 10; i--) {
      console.log(i);
    }
  4. (编程)用 splice 方法将 [1, 2, 3, 4, 5] 改为 [1, 2, 'X', 4, 5]

    js
    const arr19 = [1, 2, 3, 4, 5];
    arr19.________(___________);
参考答案
  1. A 解析:在索引为 1 的元素(2)前插入了 4,结果为 [1, 4, 2, 3]
  2. javascript
    // 方法 1:传统 for
    for (let i = 0; i < arr18.length; i++) {
      console.log(arr18[i] * 2);
    }
    // 方法 2:for...of
    for (const item of arr18) {
      console.log(item * 2);
    }
    // 方法 3:for...in
    for (const key in arr18) {
      console.log(arr18[key] * 2);
    }
  3. i-- 导致 i 越来越小,循环条件 i <= 10 永远成立,形成死循环。
  4. arr19.splice(2, 1, 'X') 解析
    • 从索引 2 开始删除 1 个元素(即 3
    • 在索引 2 插入 'X'

拓展阅读

Built by Vitepress | Apache 2.0 Licensed