在我们学习数组的各种操作之前,让我们先理解一个重要的概念:不同的数据类型有不同的"能力"。
属性和方法都是数据类型的"内置能力",就像人会走路、说话、吃饭一样。
属性就像物品的特征或信息,我们用它来"查看"或"获取"信息:
属性的特点:
数据.属性名 的形式方法就像物品的功能或动作,我们用它来"执行"某些操作:
方法的特点:
数据.方法名() 的形式,注意有小括号返回值就像方法执行后给你的"回复"或"结果"。
如何处理方法的返回值:
看我们刚才的两个push()例子:
对比这两种做法:
newLength 变量就像我们在数据类型基础中学习的变量一样,TypeScript 也能智能推断类型。让我们先回忆一下变量类型推断:
同样地,TypeScript 也能智能推断数组的类型。在前面学习的数组创建中,我们都没有显式声明类型,TypeScript 是如何自动推断类型的呢?让我们详细看看:
这是你第一次接触 number[] 和 string[] 这样的类型语法!让我们详细理解一下:
什么是 number[]?
number:表示数字类型[]:表示数组number[]:合起来就是"数字数组类型",即只能存储数字的数组类型什么是 string[]?
string:表示字符串类型[]:表示数组string[]:合起来就是"字符串数组类型",即只能存储字符串的数组类型现在让我们继续学习 TypeScript 是如何自动推断这些类型的!
在数组的学习中,我们都是创建数组并立即放入元素,TypeScript 可以通过以下过程自动推断类型:
TypeScript 的智能推断过程:
当我们写 let scores = [100, 85, 92]; 时,TypeScript 会这样分析:
[100, 85, 92]scores 变量的类型确定为 number[]同样的过程也适用于字符串数组:
["小明", "小红", "小刚"]names 变量的类型确定为 string[]为什么这样够用?
类型明确:从初始值就能清楚判断数组应该存储什么类型的数据
代码简洁:不需要写额外的类型声明语法,代码更干净
自动保护:一旦类型确定,TypeScript 就会阻止错误类型的操作。比如我们通过 [100, 85, 92] 创建的数组被自动推断为数字数组后,就无法添加字符串类型的元素:
有时候我们需要先声明数组,稍后才添加元素,这时就需要显式声明类型:
让我们先思考一个问题:
你觉得这个 emptyScores 数组是什么类型的呢?看起来它应该是一个数字数组,对吧?
但是 TypeScript 有个问题:当它看到 let emptyScores = []; 这个空数组时,里面没有任何元素来判断类型。它不知道这个数组将来要存储数字、字符串,还是其他类型的数据。
TypeScript 的推断:any[]
TypeScript 也面临同样的问题,当它看到空数组 [] 时,由于没有任何元素来判断类型,它会推断为 any[] 类型。
什么是 any 类型?
any 表示"任何的"、"任意的"any 类型表示"任何类型",可以是数字、字符串、布尔值等任何类型any 类型完全跳过了 TypeScript 的类型检查any 类型,因为它失去了 TypeScript 的核心优势所以,let emptyScores = []; 被推断为 any[],意味着这个数组可以存储任何类型的数据。
让我们看看这个any[]数组类型的实际影响:
现在让我们看看正确的做法,通过显式类型声明来获得类型保护:
这就是类型保护的价值:
通过显式声明 number[] 类型,我们获得了完整的 TypeScript 类型保护!
让我们回忆一下在数据类型基础中学到的类型指定语法。在变量数据类型课程中,我们学习了:
冒号 : 是类型分隔符:
现在让我们把这个知识应用到数组类型声明中:
数组类型声明的详细理解:
let - 变量声明关键字变量名 - 给数组起的名字(如 numbers, strings): - 类型分隔符(和之前学的一样)数据类型[] - 数组类型:
number[] - 数字数组类型string[] - 字符串数组类型boolean[] - 布尔值数组类型= [] - 赋值,创建一个空数组关键理解:
let scores = [10, 20, 30] → TypeScript 自动识别为 number[]let scores: number[] = [] → 我们明确告诉 TypeScript 这是数字数组类型使用自动推断(推荐):
使用显式声明(必要时):
重要提醒: 在实际编程中,大多数情况下我们使用自动推断,只有在创建空数组或确实需要时才使用显式声明。这能帮助我们保持代码的简洁性,同时享受 TypeScript 的类型安全保护!
现在让我们继续学习数组的各种操作方法!
数组最重要的特性是可以动态改变:我们可以添加新元素或删除现有元素。
push() 方法用于在数组的末尾添加一个或多个元素。
重要特点:
push() 会返回新数组的长度push() 的重要特点:
scores.push(78)scores.push(95, 88)push() 的括号内用逗号分隔多个值理解 push() 的工作过程:
scores.push(78) 把数字78添加到数组末尾
[85, 92] 变成 [85, 92, 78]scores.push(95, 88) 同时添加多个数字到数组末尾
[85, 92, 78] 变成 [85, 92, 78, 95, 88]⚠️ 重要:类型一致性
scores 是一个数字数组,只能存储数字正确的做法:
错误的做法:
pop() 方法用于删除并返回数组的最后一个元素。
理解 pop() 的工作过程和返回值:
numbers.pop() 删除并返回最后一个元素
[10, 20, 30, 40] 变成 [10, 20, 30]返回值的使用方式:
let lastScore = scores.pop();scores.pop(); (只关心删除动作)什么时候需要保存返回值:
什么时候可以忽略返回值:
unshift() 方法用于在数组的开头添加一个或多个元素。
重要特点:
unshift() 会返回新数组的长度push() 一样,我们通常忽略这个返回值,只关心添加元素的动作理解 unshift() 的工作过程:
numbers.unshift(20) 把20添加到数组开头
[30, 40] 变成 [20, 30, 40]numbers.unshift(5, 10) 同时添加多个数字到数组开头
[20, 30, 40] 变成 [5, 10, 20, 30, 40]shift() 方法用于删除并返回数组的第一个元素。
理解 shift() 的工作过程:
numbers.shift() 删除并返回第一个元素10[10, 20, 30] 变成 [20, 30]join() 方法用于将数组中的所有元素连接成一个字符串。
理解 join() 的工作过程:
join() 不传参数时,默认用逗号 , 作为分隔符join("分隔符") 可以指定任意字符串作为分隔符join() 返回一个新的字符串,不修改原数组join() 的常用场景:
今天我们系统学习了数组的高级操作和TypeScript类型系统,按照学习顺序总结:
数据.属性 和 数据.方法() 的使用区别number[]、string[] 等类型声明语法any[] 的风险push() 在末尾添加,unshift() 在开头添加pop() 从末尾删除,shift() 从开头删除join() 将数组连接成字符串,支持自定义分隔符这些高级操作和类型系统知识,让我们能够更安全、更灵活地管理数组数据,为后续学习更复杂的数组操作和数据结构打下了坚实基础。掌握数组的各种方法和TypeScript类型保护,将大大提升我们编程的代码质量和可靠性!