7 第5章:数组与对象
7.1 🎯 学习目标
- 掌握数组的创建与常用操作方法
- 理解对象字面量与接口的使用
- 熟练使用解构赋值
- 掌握展开运算符与剩余运算符
7.2 5.1 数组
7.2.1 📚 数组的创建
数组是用于存储多个值的容器。
// 方式一:数组字面量(推荐)
let numbers: number[] = [1, 2, 3, 4, 5]
let fruits: string[] = ['苹果', '香蕉', '橙子']
// 方式二:泛型数组类型
let scores: Array<number> = [90, 85, 92, 88]
let names: Array<string> = ['张三', '李四', '王五']
// 方式三:创建空数组后添加元素
let emptyArr: number[] = []
emptyArr.push(1)
emptyArr.push(2)7.2.2 📊 数组常用属性和方法
let arr: number[] = [10, 20, 30, 40, 50]
// 属性
arr.length // 5(数组长度)
// 添加/删除元素
arr.push(60) // 末尾添加 → [10,20,30,40,50,60]
arr.pop() // 末尾删除 → 60
arr.unshift(5) // 开头添加 → [5,10,20,30,40,50]
arr.shift() // 开头删除 → 5
// 查找元素
arr.indexOf(30) // 2(返回索引,找不到返回-1)
arr.includes(30) // true(是否包含)
arr.find(x => x > 25) // 30(返回第一个符合条件的元素)
arr.findIndex(x => x > 25) // 2(返回索引)
// 数组转换
arr.map(x => x * 2) // [20,40,60,80,100](转换每个元素)
arr.filter(x => x > 25) // [30,40,50](过滤)
arr.reduce((acc, curr) => acc + curr, 0) // 150(累积)
arr.sort((a, b) => a - b) // 排序(原数组被修改)
arr.reverse() // 反转(原数组被修改)
// 数组切片
arr.slice(1, 4) // [20,30,40](截取,不包含结束索引)
arr.splice(2, 1) // 从索引2开始删除1个元素(原数组被修改)
// 数组合并
let arr2: number[] = [60, 70]
arr.concat(arr2) // [10,20,30,40,50,60,70]🎮 互动演示:数组方法可视化
选择数组方法,查看执行效果:
原始数组:[10, 20, 30, 40, 50]
7.3 5.2 对象
7.3.1 📦 对象字面量
对象用于存放键值对集合。
// 创建对象
let person = {
name: '张三',
age: 25,
city: '北京',
isStudent: true
}
// 访问属性
person.name // '张三'(点号表示法)
person['age'] // 25(方括号表示法)
// 修改属性
person.age = 26
person['city'] = '上海'
// 添加新属性
person.email = 'zhangsan@example.com'
// 删除属性
delete person.isStudent7.3.2 📋 接口(Interface)
接口用于定义对象的结构,提供类型检查和代码提示。
// 定义接口
interface Person {
name: string
age: number
email?: string // 可选属性
readonly id: number // 只读属性
}
// 使用接口
let user: Person = {
id: 1,
name: '张三',
age: 25
}
// user.id = 2 // ❌ 错误:不能修改只读属性
// 函数类型接口
interface GreetFunction {
(name: string): string
}
let greet: GreetFunction = (name) => 'Hello, ' + name + '!'接口 vs 类型别名
interface 和 type 都可以定义对象类型,但有一些区别: - interface 可以被扩展(extends)和实现(implements) - type 可以使用联合类型、交叉类型等更复杂的类型操作 - 一般建议:定义对象形状用 interface,其他复杂类型用 type
7.3.3 🏗️ 对象解构赋值
解构赋值允许从对象中提取值并赋值给变量。
let person = {
name: '张三',
age: 25,
city: '北京'
}
// 基本解构
let { name, age } = person
console.log(name) // '张三'
console.log(age) // 25
// 重命名变量
let { name: personName, city: personCity } = person
console.log(personName) // '张三'
// 默认值
let { name, email = '未设置' } = person
console.log(email) // '未设置'(person中没有email属性)
// 嵌套解构
let user = {
id: 1,
info: {
name: '李四',
age: 30
}
}
let { info: { name, age } } = user
console.log(name, age) // '李四' 307.4 5.3 展开运算符与剩余运算符
7.4.1 📦 展开运算符(…)
展开运算符用于展开数组或对象的元素。
// 展开数组
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
let combined = [...arr1, ...arr2]
console.log(combined) // [1, 2, 3, 4, 5, 6]
// 复制数组
let original = [1, 2, 3]
let copy = [...original] // 创建新数组,不是引用
copy.push(4)
console.log(original) // [1, 2, 3](原数组未被修改)
// 展开对象
let obj1 = { x: 1, y: 2 }
let obj2 = { ...obj1, z: 3 }
console.log(obj2) // { x: 1, y: 2, z: 3 }
// 合并对象(后面的属性会覆盖前面的)
let defaults = { theme: 'light', lang: 'zh' }
let userPrefs = { theme: 'dark' }
let prefs = { ...defaults, ...userPrefs }
console.log(prefs) // { theme: 'dark', lang: 'zh' }7.4.2 📦 剩余运算符(…)
剩余运算符用于收集多个值。
// 剩余参数(函数参数中)
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0)
}
console.log(sum(1, 2, 3, 4)) // 10
// 剩余元素(数组解构中)
let [first, second, ...rest] = [1, 2, 3, 4, 5]
console.log(first) // 1
console.log(second) // 2
console.log(rest) // [3, 4, 5]
// 剩余属性(对象解构中)
let { name, ...otherProps } = { name: '张三', age: 25, city: '北京' }
console.log(name) // '张三'
console.log(otherProps) // { age: 25, city: '北京' }🎮 互动练习:展开与剩余运算符
展开运算符 ...
合并数组/对象:
let arr1 = [1,2];
let arr2 = [3,4];
let merged = [...arr1, ...arr2];
// [1,2,3,4]
let arr2 = [3,4];
let merged = [...arr1, ...arr2];
// [1,2,3,4]
剩余运算符 ...
收集剩余值:
let [a, b, ...rest] = [1,2,3,4,5];
// a=1, b=2
// rest=[3,4,5]
// a=1, b=2
// rest=[3,4,5]
💡 记忆技巧:
- 在 右侧(赋值语句右边):展开运算符 → 展开元素
- 在 左侧(赋值语句左边):剩余运算符 → 收集元素
- 在 右侧(赋值语句右边):展开运算符 → 展开元素
- 在 左侧(赋值语句左边):剩余运算符 → 收集元素
7.5 5.4 实用案例
7.5.1 📊 数据处理案例
// 学生成绩处理
interface Student {
name: string
scores: number[]
}
let students: Student[] = [
{ name: '张三', scores: [85, 90, 78] },
{ name: '李四', scores: [92, 88, 95] },
{ name: '王五', scores: [76, 82, 79] }
]
// 计算每个学生平均分
let studentAverages = students.map(student => {
let avg = student.scores.reduce((a, b) => a + b, 0) / student.scores.length
return {
name: student.name,
average: Math.round(avg * 10) / 10
}
})
console.log(studentAverages)
// [
// { name: '张三', average: 84.3 },
// { name: '李四', average: 91.7 },
// { name: '王五', average: 79 }
// ]
// 找出平均分最高的学生
let topStudent = studentAverages.reduce((top, current) =>
current.average > top.average ? current : top
)
console.log(`最高分:${topStudent.name},平均分:${topStudent.average}`)7.5.2 🗂️ 对象数组去重
// 根据 id 去重
interface Item {
id: number
value: string
}
let items: Item[] = [
{ id: 1, value: 'A' },
{ id: 2, value: 'B' },
{ id: 1, value: 'A' }, // 重复
{ id: 3, value: 'C' }
]
// 方法一:使用 Set
let uniqueItems1 = Array.from(
new Map(items.map(item => [item.id, item])).values()
)
// 方法二:使用 filter + findIndex
let uniqueItems2 = items.filter(
(item, index, self) => index === self.findIndex(t => t.id === item.id)
)
console.log(uniqueItems1) // [{id:1,value:'A'}, {id:2,value:'B'}, {id:3,value:'C'}]7.6 📝 本章小结
本章我们学习了ArkTS中的数组与对象:
- 数组:创建方式、常用方法(push/pop/map/filter/reduce等)
- 对象:对象字面量、属性访问与修改
- 接口:定义对象结构,提供类型检查
- 解构赋值:从对象/数组中提取值
- 展开与剩余运算符:
...的两种用法
7.7 ✏️ 练习
- 创建一个包含5个学生成绩的数组,使用
map将每个成绩加上5分(满分100) - 使用
filter筛选出数组中大于平均值的元素 - 定义一个
Book接口,包含title、author、year属性,创建一个书籍对象数组 - 使用展开运算符合并两个对象,并处理属性冲突