← 编程学习中心
📖

Preparation

8 个课程
1
如何学习编程
2
计算机基础
3
键盘初识与基准键位
4
字母与数字基础
5
Shift键魔法
6
编程符号专精
7
功能键与修饰键
8
键盘学习总结与进阶
📚

Basics

22 个课程
1
什么是编程?
2
Hello World - 你的第一个程序
3
变量基础概念 - 给信息贴标签
4
变量赋值和操作 - 变量的高级用法
5
数据类型基础 - 数字和字符串
6
基础运算符 - 数字运算王国
7
布尔类型与比较运算符 - 程序的判断基础
8
条件判断基础 - 让程序学会做决定
9
变量作用域 - 变量的生存范围
10
条件语句进阶 - 复杂判断与嵌套结构
11
逻辑运算符 - 简化复杂条件判断
12
循环语句 - 程序的重复机器
13
循环进阶 - break、continue与循环控制
14
嵌套循环与作用域
15
循环调试实战技巧
16
循环不变量 - 理解循环的数学规律
17
数组基础 - 数据的收纳盒
18
数组操作方法 - 添加、删除和管理
19
数组高级 - 探索数组的强大功能
20
引用概念 - 变量的不同行为
21
函数基础 - 解决重复代码的秘密武器
22
函数实践与应用 - 巩固基础,实战应用
🚀

Intermediate

11 个课程
1
从控制台到画布 - p5.js初体验
2
图形绘制工具箱 - 基础图形函数
3
让世界多彩 - 颜色系统详解
4
文字的艺术 - 文本绘制与样式
5
球体动起来 - 动画基础入门
6
球体的交互魔法 - 鼠标与条件判断
7
面向对象编程 - Class类与实例
8
球的家族 - 循环与数组应用
9
球的个性 - 函数封装与参数化
10
球的变身 - 形状模式与高级绘制
11
球的世界 - 综合创作项目
🎯

Advanced

6 个课程
1
对象类型
2
对象类型应用
3
自定义类型
4
函数进阶 - 箭头函数与高级编程技巧
5
内置方法 - 字符串与数组的魔法工具
6
Switch语句与字符串模板 - 更优雅的代码表达
← 编程学习中心
📖

Preparation

8 个课程
1
如何学习编程
2
计算机基础
3
键盘初识与基准键位
4
字母与数字基础
5
Shift键魔法
6
编程符号专精
7
功能键与修饰键
8
键盘学习总结与进阶
📚

Basics

22 个课程
1
什么是编程?
2
Hello World - 你的第一个程序
3
变量基础概念 - 给信息贴标签
4
变量赋值和操作 - 变量的高级用法
5
数据类型基础 - 数字和字符串
6
基础运算符 - 数字运算王国
7
布尔类型与比较运算符 - 程序的判断基础
8
条件判断基础 - 让程序学会做决定
9
变量作用域 - 变量的生存范围
10
条件语句进阶 - 复杂判断与嵌套结构
11
逻辑运算符 - 简化复杂条件判断
12
循环语句 - 程序的重复机器
13
循环进阶 - break、continue与循环控制
14
嵌套循环与作用域
15
循环调试实战技巧
16
循环不变量 - 理解循环的数学规律
17
数组基础 - 数据的收纳盒
18
数组操作方法 - 添加、删除和管理
19
数组高级 - 探索数组的强大功能
20
引用概念 - 变量的不同行为
21
函数基础 - 解决重复代码的秘密武器
22
函数实践与应用 - 巩固基础,实战应用
🚀

Intermediate

11 个课程
1
从控制台到画布 - p5.js初体验
2
图形绘制工具箱 - 基础图形函数
3
让世界多彩 - 颜色系统详解
4
文字的艺术 - 文本绘制与样式
5
球体动起来 - 动画基础入门
6
球体的交互魔法 - 鼠标与条件判断
7
面向对象编程 - Class类与实例
8
球的家族 - 循环与数组应用
9
球的个性 - 函数封装与参数化
10
球的变身 - 形状模式与高级绘制
11
球的世界 - 综合创作项目
🎯

Advanced

6 个课程
1
对象类型
2
对象类型应用
3
自定义类型
4
函数进阶 - 箭头函数与高级编程技巧
5
内置方法 - 字符串与数组的魔法工具
6
Switch语句与字符串模板 - 更优雅的代码表达

数组操作方法 - 添加、删除和管理

🎯 理解数据类型的属性和方法

在我们学习数组的各种操作之前,让我们先理解一个重要的概念:不同的数据类型有不同的"能力"。

我们已经见过两种"点号"的使用:

加载代码编辑器...

什么是属性?什么是方法?

属性和方法都是数据类型的"内置能力",就像人会走路、说话、吃饭一样。

属性 - 用来获取信息

属性就像物品的特征或信息,我们用它来"查看"或"获取"信息:

加载代码编辑器...

属性的特点:

  • 只获取信息 - 不会改变原数据
  • 唯一属性名 - 每个属性都有自己的名字,用来区分不同的特征
  • 直接访问 - 使用 数据.属性名 的形式

方法 - 用来执行动作

方法就像物品的功能或动作,我们用它来"执行"某些操作:

加载代码编辑器...

方法的特点:

  • 执行动作 - 可能会改变原数据
  • 唯一方法名 - 每个方法都有自己的名字,用来区分不同的功能
  • 需要调用 - 使用 数据.方法名() 的形式,注意有小括号
  • 可能返回结果 - 有些方法会返回一个值,可以保存到变量中

方法的返回值

返回值就像方法执行后给你的"回复"或"结果"。

加载代码编辑器...

如何处理方法的返回值:

  1. 保存到变量 - 如果需要使用返回的结果
  2. 忽略返回值 - 如果只需要方法执行的动作,不关心返回结果

看我们刚才的两个push()例子:

加载代码编辑器...

对比这两种做法:

  • 例子1:我们需要知道新长度,所以保存到 newLength 变量
  • 例子2:我们不关心push()返回的长度,所以直接调用

🎯 数组的类型声明:从自动推断到显式声明

就像我们在数据类型基础中学习的变量一样,TypeScript 也能智能推断类型。让我们先回忆一下变量类型推断:

加载代码编辑器...

同样地,TypeScript 也能智能推断数组的类型。在前面学习的数组创建中,我们都没有显式声明类型,TypeScript 是如何自动推断类型的呢?让我们详细看看:

加载代码编辑器...

🔍 认识数组类型语法:number[] 和 string

这是你第一次接触 number[] 和 string[] 这样的类型语法!让我们详细理解一下:

什么是 number[]?

  • number:表示数字类型
  • []:表示数组
  • number[]:合起来就是"数字数组类型",即只能存储数字的数组类型

什么是 string[]?

  • string:表示字符串类型
  • []:表示数组
  • string[]:合起来就是"字符串数组类型",即只能存储字符串的数组类型

现在让我们继续学习 TypeScript 是如何自动推断这些类型的!

为什么前面不需要显式类型声明?

在数组的学习中,我们都是创建数组并立即放入元素,TypeScript 可以通过以下过程自动推断类型:

TypeScript 的智能推断过程:

当我们写 let scores = [100, 85, 92]; 时,TypeScript 会这样分析:

  1. 看到数组内容:[100, 85, 92]
  2. 逐一检查元素类型:
    • 检查第一个元素:100 是数字类型
    • 检查第二个元素:85 是数字类型
    • 检查第三个元素:92 是数字类型
  3. 得出结论:所有元素都是数字类型,所以这是一个数字数组
  4. 确定变量类型:scores 变量的类型确定为 number[]

同样的过程也适用于字符串数组:

  • 看到数组内容:["小明", "小红", "小刚"]
  • 检查所有元素:都是字符串类型
  • 得出结论:这是一个字符串数组
  • 确定变量类型:names 变量的类型确定为 string[]

为什么这样够用?

  1. 类型明确:从初始值就能清楚判断数组应该存储什么类型的数据

  2. 代码简洁:不需要写额外的类型声明语法,代码更干净

  3. 自动保护:一旦类型确定,TypeScript 就会阻止错误类型的操作。比如我们通过 [100, 85, 92] 创建的数组被自动推断为数字数组后,就无法添加字符串类型的元素:

    加载代码编辑器...

什么时候需要显式声明数组类型?

有时候我们需要先声明数组,稍后才添加元素,这时就需要显式声明类型:

空数组的类型推断问题

让我们先思考一个问题:

加载代码编辑器...

你觉得这个 emptyScores 数组是什么类型的呢?看起来它应该是一个数字数组,对吧?

但是 TypeScript 有个问题:当它看到 let emptyScores = []; 这个空数组时,里面没有任何元素来判断类型。它不知道这个数组将来要存储数字、字符串,还是其他类型的数据。

TypeScript 的推断:any[]

TypeScript 也面临同样的问题,当它看到空数组 [] 时,由于没有任何元素来判断类型,它会推断为 any[] 类型。

什么是 any 类型?

  • 英语意思:any 表示"任何的"、"任意的"
  • TypeScript 中:any 类型表示"任何类型",可以是数字、字符串、布尔值等任何类型
  • 重要特点:any 类型完全跳过了 TypeScript 的类型检查
  • 使用建议:我们一般不会主动使用 any 类型,因为它失去了 TypeScript 的核心优势

所以,let emptyScores = []; 被推断为 any[],意味着这个数组可以存储任何类型的数据。

让我们看看这个any[]数组类型的实际影响:

加载代码编辑器...

现在让我们看看正确的做法,通过显式类型声明来获得类型保护:

加载代码编辑器...

这就是类型保护的价值:

  • 运行前的类型检查:TypeScript 在程序运行之前就检查类型错误,提前发现问题
  • 数据一致性:确保数组中所有元素都是相同类型
  • 运行时安全:避免后续处理时出现意外的类型转换错误

通过显式声明 number[] 类型,我们获得了完整的 TypeScript 类型保护!

数组类型的语法

让我们回忆一下在数据类型基础中学到的类型指定语法。在变量数据类型课程中,我们学习了:

冒号 : 是类型分隔符:

  • 告诉 TypeScript:"接下来我要指定这个变量的类型"
  • 把变量名和类型名分开

现在让我们把这个知识应用到数组类型声明中:

加载代码编辑器...

数组类型声明的详细理解:

  1. let - 变量声明关键字
  2. 变量名 - 给数组起的名字(如 numbers, strings)
  3. : - 类型分隔符(和之前学的一样)
  4. 数据类型[] - 数组类型:
    • number[] - 数字数组类型
    • string[] - 字符串数组类型
    • boolean[] - 布尔值数组类型
  5. = [] - 赋值,创建一个空数组

关键理解:

  • 类型推断:let scores = [10, 20, 30] → TypeScript 自动识别为 number[]
  • 显式声明:let scores: number[] = [] → 我们明确告诉 TypeScript 这是数字数组类型

何时使用哪种方式?

使用自动推断(推荐):

加载代码编辑器...

使用显式声明(必要时):

加载代码编辑器...

重要提醒: 在实际编程中,大多数情况下我们使用自动推断,只有在创建空数组或确实需要时才使用显式声明。这能帮助我们保持代码的简洁性,同时享受 TypeScript 的类型安全保护!

现在让我们继续学习数组的各种操作方法!

🎯 数组的核心操作:添加和删除

数组最重要的特性是可以动态改变:我们可以添加新元素或删除现有元素。

在数组末尾添加元素:push()

push() 方法用于在数组的末尾添加一个或多个元素。

重要特点:

  • push() 会返回新数组的长度
  • 但我们通常忽略这个返回值,只关心添加元素的动作
加载代码编辑器...

push() 的重要特点:

  1. 可以添加一个元素:scores.push(78)
  2. 可以同时添加多个元素:scores.push(95, 88)
  3. 多个元素用逗号分隔:在 push() 的括号内用逗号分隔多个值

理解 push() 的工作过程:

  1. scores.push(78) 把数字78添加到数组末尾

    • 数组从 [85, 92] 变成 [85, 92, 78]
    • 数组长度从2变成3
  2. scores.push(95, 88) 同时添加多个数字到数组末尾

    • 数组从 [85, 92, 78] 变成 [85, 92, 78, 95, 88]
    • 数组长度从3变成5

⚠️ 重要:类型一致性

  • scores 是一个数字数组,只能存储数字
  • 不能在数字数组中添加字符串或其他类型的数据
  • TypeScript 会检查类型错误,确保数组类型的一致性

正确的做法:

加载代码编辑器...

错误的做法:

加载代码编辑器...

从数组末尾删除元素:pop()

pop() 方法用于删除并返回数组的最后一个元素。

加载代码编辑器...

理解 pop() 的工作过程和返回值:

  1. numbers.pop() 删除并返回最后一个元素

    • 删除元素40
    • 返回值:40(可以保存到变量中)
    • 数组从 [10, 20, 30, 40] 变成 [10, 20, 30]
  2. 返回值的使用方式:

    • 保存返回值:let lastScore = scores.pop();
    • 忽略返回值:scores.pop(); (只关心删除动作)
  3. 什么时候需要保存返回值:

    • 当你需要知道被删除的元素是什么时
    • 当需要使用被删除的值进行其他操作时
  4. 什么时候可以忽略返回值:

    • 当你只想要删除元素,不关心被删除的是什么时

在数组开头添加元素:unshift()

unshift() 方法用于在数组的开头添加一个或多个元素。

重要特点:

  • unshift() 会返回新数组的长度
  • 和 push() 一样,我们通常忽略这个返回值,只关心添加元素的动作
加载代码编辑器...

理解 unshift() 的工作过程:

  1. numbers.unshift(20) 把20添加到数组开头

    • 数组从 [30, 40] 变成 [20, 30, 40]
    • 数组长度从2变成3
  2. numbers.unshift(5, 10) 同时添加多个数字到数组开头

    • 数组从 [20, 30, 40] 变成 [5, 10, 20, 30, 40]
    • 数组长度从3变成5
    • 注意:5和10按照添加的顺序出现在数组开头

从数组开头删除元素:shift()

shift() 方法用于删除并返回数组的第一个元素。

加载代码编辑器...

理解 shift() 的工作过程:

  1. numbers.shift() 删除并返回第一个元素10
  2. 其余元素向前移动
  3. 数组从 [10, 20, 30] 变成 [20, 30]

将数组转换为字符串:join()

join() 方法用于将数组中的所有元素连接成一个字符串。

加载代码编辑器...

理解 join() 的工作过程:

  1. 默认行为:join() 不传参数时,默认用逗号 , 作为分隔符
  2. 自定义分隔符:join("分隔符") 可以指定任意字符串作为分隔符
  3. 返回值:join() 返回一个新的字符串,不修改原数组
  4. 实际用途:常用于将数组数据显示为可读的字符串格式

join() 的常用场景:

加载代码编辑器...

总结

今天我们系统学习了数组的高级操作和TypeScript类型系统,按照学习顺序总结:

数据类型的属性和方法

  1. 属性和方法概念 - 理解了属性用于获取信息,方法用于执行动作
  2. 方法的返回值 - 学会了保存和使用方法的返回结果
  3. 点号语法 - 掌握了 数据.属性 和 数据.方法() 的使用区别

TypeScript 数组类型系统

  1. 类型自动推断 - TypeScript 能够根据初始元素自动推断数组类型
  2. 数组类型语法 - 学习了 number[]、string[] 等类型声明语法
  3. 空数组类型问题 - 理解了空数组会被推断为 any[] 的风险
  4. 显式类型声明 - 掌握了在需要时显式声明数组类型以获得类型保护

数组操作方法

  1. 添加元素 - push() 在末尾添加,unshift() 在开头添加
  2. 删除元素 - pop() 从末尾删除,shift() 从开头删除
  3. 数组转换 - join() 将数组连接成字符串,支持自定义分隔符
  4. 方法返回值处理 - 学会了何时保存返回值,何时忽略返回值

这些高级操作和类型系统知识,让我们能够更安全、更灵活地管理数组数据,为后续学习更复杂的数组操作和数据结构打下了坚实基础。掌握数组的各种方法和TypeScript类型保护,将大大提升我们编程的代码质量和可靠性!

Previous lesson
Previous
数组基础 - 数据的收纳盒
Next
数组高级 - 探索数组的强大功能
Next lesson