← 编程学习中心
📖

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到n的和,其中n可以是不同的值。

没有函数的重复代码

假设我们需要多次计算数列的和。在不同的数学问题中,我们可能需要计算:

  • 从1加到10的和:1+2+3+...+10
  • 从1加到20的和:1+2+3+...+20
  • 从1加到100的和:1+2+3+...+100

每次我们都写出完整的计算代码:

加载代码编辑器...

问题分析:

  • 代码重复:同样的循环逻辑写了3遍
  • 容易出错:复制粘贴时容易漏掉某些修改
  • 维护困难:如果要修改计算逻辑,需要修改3个地方
  • 参数变化:每个任务的参数都不同(10、20、100)

使用函数的解决方案

现在让我们用函数来解决这个问题。先不要关注函数内部的细节,我们后面会详细讲解。现在只需要感受函数带来的好处:

加载代码编辑器...

函数的价值:

  • 解决重复:把相同的计算逻辑只写一次
  • 提高效率:修改计算逻辑只需要改一个地方
  • 代码整洁:让程序更容易阅读和维护

函数的核心概念

什么是函数?

函数就是一段有名字的代码块,它可以接收输入数据,进行处理,然后返回结果。

生活类比:洗衣机

  • 输入:放入的衣服、选择的洗衣模式
  • 处理(函数体):洗衣机内部的清洗过程
  • 输出(返回值):干净的衣服

就像洗衣机可以根据不同的衣服和模式产生不同的结果,函数也可以根据不同的输入产生不同的输出。

函数的四个核心部分

基于洗衣机的类比,让我们理解函数需要哪四个核心部分:

  1. 函数名称(Function Name)

    • 就像洗衣机的品牌名称(如"海尔"、"西门子")
    • 用来标识和区分不同的函数
    • 让我们知道这是哪个函数,它有什么用途
  2. 输入参数(Input Parameters)

    • 就像洗衣机接收的衣服和洗衣模式
    • 函数接收的输入数据
    • 让函数能够处理不同的情况和需求
  3. 函数体(Function Body)

    • 就像洗衣机内部的实际清洗过程
    • 包含具体的处理逻辑和计算步骤
    • 这是函数真正干活的地方
  4. 返回结果(Return Value)

    • 就像洗衣机输出的干净衣服
    • 函数处理完成后输出的结果
    • 将处理结果返回给调用者

现在让我们看看具体的 sum 函数是如何对应这四个部分的:

加载代码编辑器...

我们现在以上面的 sum 函数为例,进行详细的语法讲解:

函数的完整语法结构:

  1. function 关键字

    • 告诉 TypeScript 我们要定义一个函数
    • 这是所有函数定义的开始
  2. 函数名称:sum

    • 给函数起一个名字,方便调用
    • 就像变量名一样,函数名要符合命名规则
  3. 输入参数列表:(n: number)

    • 用圆括号 () 包围
    • 可以支持多个参数,用逗号分隔(后面会学到)
    • 每个参数必须指定类型:参数名: 类型
    • 这里 n: number 表示参数名为 n,类型为数字
    • 重要:参数类型不能依赖自动推断,必须显式声明(因为在定义的时候无法推断)
    • 语法类比:n: number 的语法结构和使用 let n: number 很相似,只是没有 let 关键字
  4. 返回类型:: number

    • 在参数列表的后面,用冒号 : 指定
    • 只有类型,没有名称(因为返回值不需要名字)
    • 告诉调用者这个函数会返回什么类型的数据
    • 这里 : number 表示函数承诺返回一个数字
  5. 函数体:{...}

    • 用大括号 {} 包围的代码块
    • 包含具体的处理逻辑和计算步骤
  6. return 关键字

    • 在函数体内部,用来指定返回值
    • return total; 表示将 total 的值作为函数的返回结果
    • return 后面的值类型必须与声明的返回类型一致

完整语法模板:

function 函数名(参数1: 类型1, 参数2: 类型2): 返回类型 {
  // 函数体:处理逻辑
  return 返回值; // 必须与返回类型匹配
}

函数调用的语法

定义完函数后,我们需要调用函数来使用它。让我们学习函数调用的语法:

回顾:我们已经见过的"调用"

在之前的课程中,我们已经多次接触过"调用"的概念:

在数组课程中,我们学过调用方法:

加载代码编辑器...

我们一直在使用 console.log():

加载代码编辑器...

现在学习调用我们自己定义的函数:

加载代码编辑器...

调用方法的特点:

  • 语法:变量名.方法名(参数)(注意中间的点号 .)
  • 前提:必须先有一个数据类型的变量(对象),array.push() 中的 array 是数组类型的变量,console.log() 中的 console 是系统控制台类型的变量
  • 原理:我们调用的是这个数据类型"附带的"功能方法

调用函数的特点:

  • 语法:函数名(参数)(没有点号,直接使用函数名)

虽然语法不同,但本质上是相同的:

  • 都是执行某个功能块
  • 都可以传入参数
  • 都可以获得返回结果
  • 都是编程中的"调用"概念

💡 提示: 关于数据类型和对象的概念,我们很快就会在后续课程中详细学习。现在你只需要理解:

  • array 和 console 都是某种数据类型的变量
  • 它们自带了一些方法(如 push、log)
  • 我们通过 变量名.方法名() 的形式来使用这些方法

函数调用的详细解析和执行流程

让我们通过一个完整的例子来分析函数调用的每个步骤:

加载代码编辑器...

函数调用 sum(5) 的详细分解:

  1. 函数名:sum

    • 告诉程序要调用哪个函数
    • 必须与定义时的函数名完全一致
  2. 圆括号 ()

    • 表示这是一个函数调用
    • 所有参数都要放在圆括号内
  3. 参数 5

    • 要传递给函数的具体值
    • 5 会被赋值给函数定义中的参数 n
    • 类型匹配:5 是 number 类型,与 n: number 的类型要求一致
  4. 赋值操作 let result = sum(5)

    • 函数执行完后返回 15
    • 返回值 15 被保存到变量 result 中
    • TypeScript 自动推断 result 为 number 类型

函数调用的类型检查和类型推断

让我们用一个完整的 sum 函数例子来说明 TypeScript 的类型检查和类型推断:

加载代码编辑器...

TypeScript 的自动类型推断:

当我们调用 sum(10) 时,TypeScript 会:

  1. 检查参数类型:确认 10 是 number 类型,匹配 n: number 的要求
  2. 推断返回值类型:根据函数声明的 : number,自动将 result1 推断为 number 类型

函数调用的基本语法

基于上面的分析,我们可以总结出函数调用的通用语法结构:

直接调用(不保存返回值):

函数名(参数1, 参数2, ...);

保存返回值到变量:

let 变量名 = 函数名(参数1, 参数2, ...);

语法要点:

  • 函数名:必须与定义时的名称完全一致
  • 圆括号:表示函数调用,所有参数都放在括号内
  • 参数:按顺序传递,类型必须匹配定义时的参数类型
  • 返回值:可以保存到变量中,也可以直接使用

多个参数的函数

函数可以接收多个参数,这让函数能够处理更复杂的数据和逻辑。

多个参数的定义和调用

让我们看一个完整的例子,包含函数定义和调用,你可以直接运行这些代码:

加载代码编辑器...

参数定义规则:

  1. 参数分隔:多个参数用逗号 , 分隔
  2. 每个参数都要有类型:参数名: 类型
  3. 顺序重要:参数的顺序在调用时必须保持一致
  4. 类型声明:每个参数都必须明确声明类型

调用要点:

  • 按顺序传递:第一个值传给第一个参数,第二个值传给第二个参数,以此类推
  • 类型匹配:传递的值类型必须与参数类型匹配
  • 数量一致:传递的参数数量必须与定义的参数数量一致

函数调用的常见用途

让我们通过一个完整的例子来演示函数调用的各种常见用途:

加载代码编辑器...

函数调用的核心原理

通过上面的例子,我们可以理解函数调用的一个核心概念:函数调用的结果就是一个值,这个值可以用在任何需要它的地方。

理解复杂的函数嵌套调用

让我们重点分析 add(add(1, 2), add(3, 4)) 这个嵌套调用:

执行顺序:

  1. 先计算内层的 add(1, 2),得到结果 3
  2. 再计算内层的 add(3, 4),得到结果 7
  3. 最后计算外层的 add(3, 7),得到最终结果 10

关键理解: 函数调用的结果就是一个普通的数值,可以:

  1. 赋值给变量:let result = add(1, 2);
  2. 直接进行比较:if (add(1, 2) >= 3)
  3. 再次传递给函数作为参数:add(add(1, 2), add(3, 4))

这就是为什么函数调用可以像数学公式一样灵活使用——因为函数的返回值就是一个普通的值!

函数的各种功能特性

现在让我们通过不同的例子来了解函数的更多功能:

支持0个参数

有些函数不需要任何输入,它们执行固定的任务:

加载代码编辑器...

无参数函数的特点:

  • 函数名后面的括号 () 是空的

3. 没有返回值

有些函数只执行操作,不返回结果。这时候我们需要使用 void 类型。

什么是 void 类型?

void 是 TypeScript 中的一个特殊类型,表示"没有任何值"或"没有返回值"。

void 的英文含义:void 在英语中的意思是"空的"、"空洞的"、"无效的"。在编程中,这个含义很形象:

  • 空的返回值:函数的返回值是空的,什么都没有
  • 空洞的结果:函数执行后不产生任何可用的结果
  • 无效的返回:返回值是无效的,不能用于任何计算或操作

就像 number 表示数字类型,string 表示字符串类型一样,void 也是一种类型,但它特殊的地方在于:

  • number 类型:函数会返回一个数字(如 5, 3.14)
  • string 类型:函数会返回一个字符串(如 "hello", "你好")
  • void 类型:函数不会返回任何值,返回值是"空的"(void)

void 函数的示例

让我们看几个 void 函数的例子:

加载代码编辑器...

void 类型的特点和使用规则

  1. : void 表示不返回值

    • 在函数声明的返回类型位置写 : void
    • 告诉 TypeScript 这个函数不会返回任何值
  2. 函数内部的 return 语句

    • 可以使用 return;(空 return)来提前结束函数
    • 也可以完全不写 return,函数执行完毕后自动结束
    • 不能 return 任何具体值:return 5; 或 return "hello"; 都是错误的
  3. 调用 void 函数

    • void 函数的调用就是执行操作,不能保存到变量
    • 因为它不返回任何值,所以 let result = showPlayerInfo(...) 是没有意义的

为什么需要 void 类型?

  • 明确意图:让其他开发者知道这个函数只是执行操作,不返回值
  • 类型安全:TypeScript 会检查 void 函数,确保不会意外返回值
  • 代码清晰:提高代码的可读性和维护性

4. 支持自动推断返回值

TypeScript 可以自动推断函数的返回值类型,就像变量一样:

加载代码编辑器...

自动推断的规则:

  • 如果函数有明确的 return 语句,TypeScript 会推断返回类型
  • 如果函数没有 return 语句,会推断为 void

⚠️ 我们的建议:明确写出返回类型

虽然 TypeScript 可以自动推断返回值类型,但我们建议你总是明确写出返回类型:

加载代码编辑器...

为什么建议明确写出返回类型?

  1. 代码可读性:一眼就能看出函数返回什么类型
  2. 类型安全:避免意外的返回类型变化

5. 函数定义和调用的顺序

TypeScript 对函数顺序的灵活性

在 TypeScript 中,函数的定义和调用没有严格的顺序要求。你可以:

  1. 先定义函数,然后调用
  2. 先调用函数,然后定义函数

这两种方式都是正确的,TypeScript 都能正常工作!

示例:两种不同的顺序

方式一:先定义,后调用(推荐)

加载代码编辑器...

方式二:先调用,后定义(也正确)

加载代码编辑器...

为什么建议先定义后调用?

虽然 TypeScript 在顺序上很灵活,但我们强烈建议采用"先定义,后调用"的写法,原因如下:

  1. 便于代码理解
    • 先看到函数定义,了解函数的功能和参数
    • 再看到函数调用,就知道代码在做什么
    • 阅读代码时不需要来回翻找
  2. 符合编程惯例
    • 大多数编程语言和项目都采用这种顺序
    • 团队协作时更容易理解他人的代码

6. 函数的作用域

函数和 if 语句、for 循环一样,通过 {} 创建了自己的作用域:

加载代码编辑器...

作用域规则:

  • 内层可以访问外层:函数内部可以使用外部定义的变量
  • 外层不能访问内层:函数外部无法使用函数内部定义的变量
  • 变量生命周期:函数执行结束后,内部变量被销毁

总结

通过这节课的学习,你已经掌握了函数的核心概念和各种功能:

函数的四个核心部分

  1. 函数名称:标识和区分不同的函数
  2. 输入参数:接收外部数据,让函数能够处理不同的情况
  3. 函数体:包含具体的处理逻辑和计算步骤
  4. 返回结果:输出处理后的结果

函数的各种功能特性

  1. 多个参数:用逗号分隔,每个参数都要指定类型
  2. 无参数:函数可以不需要任何输入,执行固定任务
  3. 无返回值:使用 : void 类型,只执行操作不返回结果
  4. 类型推断:TypeScript 可以自动推断返回值类型
  5. 定义和调用顺序:TypeScript 对顺序无要求,但建议先定义后调用
  6. 作用域:函数创建独立的作用域,遵循内外层访问规则

类型安全

  • 参数类型:确保接收正确的数据类型(必须显式声明,不能依赖自动推断)
  • 返回值类型:确保返回正确的数据类型(可以显式声明或自动推断)
  • 类型检查:在代码运行前发现类型错误

函数的价值

  • 解决重复代码:把相同的逻辑只写一次
  • 提高效率:修改逻辑只需要改一个地方
  • 代码清晰:让程序更容易阅读和维护
  • 模块化设计:将复杂问题分解为小的函数

继续练习使用函数,你会发现编程变得更加高效和有趣!

Previous lesson
Previous
引用概念 - 变量的不同行为
Next
函数实践与应用 - 巩固基础,实战应用
Next lesson