首页/4

4章:函数与箭头函数:编写博客的工具函数

函数定义和类型注解

40分钟
5个学习目标

学习目标

  • 1掌握函数的类型注解
  • 2学会使用可选参数和默认参数
  • 3理解剩余参数和解构参数
  • 4掌握函数重载
  • 5为博客编写实用的工具函数

上一章我们做了什么

在上一章中,我们深入学习了接口的高级特性:

  • 可选属性(?`)让接口更灵活
  • 只读属性(readonly)保护重要数据
  • 接口继承避免重复定义
  • 函数类型接口定义函数的"形状"

我们为博客设计了完整的类型系统。但有了类型定义,还需要函数来操作这些数据。

这一章,我们会学习函数的各种特性,为博客编写实用的工具函数。

问题:没有类型约束的函数容易出错

想象一下这个场景:你写了一个格式化日期的函数。

JavaScript版本:

function formatDate(date) {
  return date.toLocaleDateString();
}

formatDate(new Date());       // "2024/1/1" - 正确
formatDate("2024-01-01");     // "2024/1/1" - 可能正确
formatDate(1234567890);       // "1970/1/15" - 错误!
formatDate(null);             // 报错!

JavaScript不会告诉你传入的参数类型不对,直到运行时才会出错。

TypeScript版本:

function formatDate(date: Date): string {
  return date.toLocaleDateString();
}

formatDate(new Date());       // ✓ 正确
formatDate("2024-01-01");     // ✗ 编译报错!类型"string"不能赋值给"Date"
formatDate(1234567890);       // ✗ 编译报错!
formatDate(null);             // ✗ 编译报错!

TypeScript在你写代码时就能发现问题。

函数类型注解的三个部分

函数的类型注解包括三个部分:

function formatDate(date: Date): string {
//                  ^^^^^^^^^^^    ^^^^^^
//                  参数类型        返回值类型
  return date.toLocaleDateString();
}

| 部分 | 作用 | 示例 | |------|------|------| | 参数类型 | 确保传入正确类型的参数 | date: Date | | 返回值类型 | 确保函数返回正确类型的值 | : string | | 函数类型 | 定义函数的完整"形状" | (date: Date) => string |

一个原则: 函数参数必须手动指定类型,返回值类型通常可以让TypeScript推断。

函数声明 vs 箭头函数

typescript
加载中...

问题:有些参数用户可能不想传

在博客系统中,我们经常需要处理可选参数。比如:

  • 格式化日期时,用户可能想指定格式,也可能用默认格式
  • 查询文章时,用户可能想分页,也可能查询所有
  • 创建文章时,用户可能想指定状态,也可能用默认值

**解决方案:可选参数和默认参数

可选参数:让用户选择

typescript
加载中...

默认参数:给参数一个默认值

typescript
加载中...

类比:可选参数就像套餐选择

把函数参数想象成餐厅套餐:

主菜(必需):红烧肉
配菜(可选):青菜 / 豆腐 / 不选
饮料(可选):可乐 / 雪碧 / 不选
  • 可选参数:你可以不选,但没有默认值
  • 默认参数:你可以不选,系统自动帮你选一个
// 可选参数:不选就是undefined
function orderMainCourse(main: string, side?: string) {}

// 默认参数:不选就是"青菜"
function orderMainCourse(main: string, side: string = "青菜") {}

问题:参数数量不确定怎么办?

有时候,函数需要接收不定数量的参数。比如:

  • 计算多个数字的和
  • 合并多个数组
  • 格式化多个标签

如果参数数量固定,我们得写很多重载。有没有更好的方法?

解决方案:剩余参数

剩余参数用 ... 语法,将多个参数收集到一个数组中。

剩余参数:收集不定数量的参数

typescript
加载中...

问题:同一个函数处理不同类型的参数?

在博客系统中,我们经常需要一个函数处理不同类型的参数。比如:

  • getPostById(id):id可能是字符串,也可能是数字
  • formatDate(date):date可能是Date对象,也可能是时间戳

如果写两个函数,名字一样但参数不同,TypeScript会报错。

解决方案:函数重载

函数重载允许我们定义多个函数签名,但只有一个实现。

函数重载:处理多种参数类型

typescript
加载中...

实战:为博客编写工具函数

现在让我们把学到的知识应用到博客项目中,编写一些实用的工具函数。

我们要实现:

  1. 日期格式化函数
  2. 文章搜索函数
  3. 标签处理函数
  4. 分页函数

博客工具函数集合

typescript
加载中...

常见错误

学习函数时,初学者常犯以下错误:

错误1:可选参数位置错误

// 错误:可选参数必须在必需参数后面
function greet(greeting?: string, name: string) {} // 编译报错!

// 正确
function greet(name: string, greeting?: string) {}

错误2:忘记处理可选参数的undefined

function greet(name: string, greeting?: string) {
  // 错误:greeting可能是undefined
  return greeting.toUpperCase(); // 可能报错!

  // 正确:先检查
  return greeting ? greeting.toUpperCase() : "HELLO";
}

错误3:剩余参数位置错误

// 错误:剩余参数必须在最后
function bad(...args: number[], last: string) {} // 编译报错!

// 正确
function good(last: string, ...args: number[]) {}

错误4:函数重载签名和实现不匹配

// 错误:实现签名不在重载列表中
function add(x: number, y: number): number; // 重载1
function add(x: string, y: string): string; // 重载2
function add(x: any, y: any): any {         // 实现
  return x + y;
}

// add(1, "2")  // 错误:没有匹配的重载

动手实践

现在轮到你了!让我们为博客编写更多的工具函数。

练习1:编写文章摘要生成函数

function generateExcerpt(content: string, maxLength: number = 100): string
  • 从文章内容中提取前maxLength个字符作为摘要
  • 如果内容长度不超过maxLength,返回原内容
  • 否则截断并添加"..."

练习2:编写文章排序函数

function sortPosts(
  posts: Post[],
  sortBy: "createdAt" | "viewCount" | "title",
  order: "asc" | "desc" = "desc"
): Post[]
  • 按指定字段排序
  • 支持升序和降序

练习3:编写标签统计函数

function countTags(posts: Post[]): Map<string, number>
  • 统计每个标签出现的次数
  • 返回Map对象

练习参考答案

typescript
加载中...

本章小结

这一章我们学习了函数的各种特性:

1. 函数类型注解

  • 参数类型:确保传入正确类型的参数
  • 返回值类型:确保函数返回正确类型的值

2. 可选参数和默认参数

  • 可选参数用 ? 标记,参数可以省略
  • 默认参数直接赋值,省略时使用默认值

3. 剩余参数

  • ... 语法,将多个参数收集到数组中
  • 必须放在参数列表最后

4. 函数重载

  • 定义多个函数签名,处理不同类型的参数
  • 只有一个函数实现

5. 实用工具函数

  • 日期格式化
  • 文章搜索和分页
  • 标签处理

下一章预告:

在下一章中,我们会学习类和面向对象编程:

  • 类的定义和构造函数
  • 访问修饰符(public、private、protected)
  • 继承和方法重写
  • 用类封装博客的核心逻辑

让我们继续吧!

交互式练习

1 / 1

函数练习

编写博客工具函数

typescript
Loading...

章节测验

问题 1 / 4得分: 0 / 4

如何标记可选参数?

A
使用!标记
B
使用?标记
C
使用*标记
D
使用#标记