📚 TypeScript 教程系列

  1. 入门与配置
  2. 基础类型与变量声明
  3. 函数
  4. 流程控制与运算符(本文)
  5. 集合类型
  6. 异步编程与错误处理
  7. 接口与类
  8. 泛型与类型组合
  9. 高级类型
  10. 模块、装饰器与工程化

⚠️ 来源声明:本文内容参考自 菜鸟教程 TypeScript 教程,仅供学习交流,版权归原作者所有。
TypeScript 在 JavaScript 之上补充了类型系统,而运算符、条件语句、循环以及迭代器/生成器构成了程序流程控制的核心。本篇将这几部分串联起来,覆盖从算术运算到生成器惰性求值的完整链路,帮助你在类型约束下写出更清晰的控制流。

运算符

运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算。例如 7 + 5 = 12 中,7、5、12 是操作数,+ 是加法运算符,= 是赋值运算符。

TypeScript 常用运算符包括:算术运算符、关系运算符、逻辑运算符、按位运算符、赋值运算符、三元/条件运算符、字符串运算符以及类型运算符。

算术运算符

假定 y = 5,下表列出了 TypeScript 支持的算术运算符:

运算符描述例子x 运算结果y 运算结果
+加法x = y + 275
-减法x = y - 235
*乘法x = y * 2105
/除法x = y / 22.55
%取模(余数)x = y % 215
++自增x = ++y66
++自增x = y++56
自减x = --y44
自减x = y–54

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var num1: number = 10
var num2: number = 2
var res: number = 0

res = num1 + num2
console.log("加: " + res)

res = num1 - num2
console.log("减: " + res)

res = num1 * num2
console.log("乘: " + res)

res = num1 / num2
console.log("除: " + res)

res = num1 % num2
console.log("余数: " + res)

num1++
console.log("num1 自增运算: " + num1)

num2--
console.log("num2 自减运算: " + num2)

输出结果:

1
2
3
4
5
6
7
:        12
: 8
: 20
: 5
余数: 0
num1 自增运算: 11
num2 自减运算: 1

关系运算符

关系运算符用于计算结果是否为 true 或者 false。假定 x = 5,下表说明了各关系运算符的运算结果:

运算符描述比较返回值
==等于x == 8false
==等于x == 5true
!=不等于x != 8true
>大于x > 8false
<小于x < 8true
>=大于或等于x >= 8false
<=小于或等于x <= 8true

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var num1: number = 5
var num2: number = 9
console.log("num1 的值为: " + num1)
console.log("num2 的值为:" + num2)

var res = num1 > num2
console.log("num1 大于 num2: " + res)
res = num1 < num2
console.log("num1 小于 num2: " + res)
res = num1 >= num2
console.log("num1 大于或等于 num2: " + res)
res = num1 <= num2
console.log("num1 小于或等于 num2: " + res)
res = num1 == num2
console.log("num1 等于 num2: " + res)
res = num1 != num2
console.log("num1 不等于 num2: " + res)

输出结果:

1
2
3
4
5
6
7
8
num1 的值为: 5
num2 的值为:9
num1 大于 num2: false
num1 小于 num2: true
num1 大于或等于 num2: false
num1 小于或等于 num2: true
num1 等于 num2: false
num1 不等于 num2: true

逻辑运算符

假定 x = 6y = 3,下表列出了 TypeScript 支持的逻辑运算符:

运算符描述例子
&&and(x < 10 && y > 1) 为 true
||or(x == 5 || y == 5) 为 false
!not!(x == y) 为 true

实例:

1
2
3
4
5
6
7
8
9
10
var avg: number = 20
var percentage: number = 90
console.log("avg 值为: " + avg + " ,percentage 值为: " + percentage)

var res: boolean = ((avg > 50) && (percentage > 80))
console.log("(avg>50)&&(percentage>80): ", res)
var res: boolean = ((avg > 50) || (percentage > 80))
console.log("(avg>50)||(percentage>80): ", res)
var res: boolean = !((avg > 50) && (percentage > 80))
console.log("!((avg>50)&&(percentage>80)): ", res)

输出结果:

1
2
3
4
avg 值为: 20 ,percentage 值为: 90
(avg>50)&&(percentage>80): false
(avg>50)||(percentage>80): true
!((avg>50)&&(percentage>80)): true

短路运算符(&& 与 ||)

  • && 运算符:如果第一个操作数为 false,就不再执行后面的判断,直接返回 false。例如 a > 5false 时,后续表达式会被跳过计算。
  • || 运算符:如果第一个操作数为 true,就不再执行后面的判断,直接返回 true。例如 a < 10true 时,后续表达式会被跳过计算。

位运算符

位运算符作用于操作数的二进制位。下表假设变量 a = 5(二进制 0101)、b = 1(二进制 0001):

运算符描述例子类似于结果十进制
&ANDx = 5 & 10101 & 000100011
|ORx = 5 | 10101 | 000101015
~取反x = ~5~01011010-6
^异或x = 5 ^ 10101 ^ 000101004
<<左移x = 5 << 10101 << 1101010
>>右移x = 5 >> 10101 >> 100102
>>>无符号右移x = 2 >>> 10010 >>> 100011

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a: number = 2
var b: number = 3
var result

result = (a & b)
console.log("(a & b) => ", result)
result = (a | b)
console.log("(a | b) => ", result)
result = (a ^ b)
console.log("(a ^ b) => ", result)
result = (~b)
console.log("(~b) => ", result)
result = (a << b)
console.log("(a << b) => ", result)
result = (a >> b)
console.log("(a >> b) => ", result)
result = (a >>> 1)
console.log("(a >>> 1) => ", result)

输出结果:

1
2
3
4
5
6
7
(a & b) =>  2
(a | b) => 3
(a ^ b) => 1
(~b) => -4
(a << b) => 16
(a >> b) => 0
(a >>> 1) => 1

赋值运算符

假定 x = 10y = 5,下表列出了赋值运算符:

运算符例子实例x 值
= (赋值)x = yx = yx = 5
+=x += yx = x + yx = 15
-=x -= yx = x - yx = 5
*=x *= yx = x * yx = 50
/=x /= yx = x / yx = 2

类似的逻辑运算符也可以与赋值运算符联合使用:<<=>>=>>>=&=|=^=

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a: number = 12
var b: number = 10

a = b
console.log("a = b: " + a)
a += b
console.log("a+=b: " + a)
a -= b
console.log("a-=b: " + a)
a *= b
console.log("a*=b: " + a)
a /= b
console.log("a/=b: " + a)
a %= b
console.log("a%=b: " + a)

输出结果:

1
2
3
4
5
6
a = b: 10
a+=b: 20
a-=b: 10
a*=b: 100
a/=b: 10
a%=b: 0

三元运算符(?)

三元运算符语法格式:

1
Test ? expr1 : expr2
  • Test:指定的条件语句。
  • expr1:如果 Testtrue 则返回该值。
  • expr2:如果 Testfalse 则返回该值。

实例:

1
2
3
var num: number = -2
var result = num > 0 ? "大于 0" : "小于 0,或等于 0"
console.log(result)

输出结果:

1
小于 0,或等于 0

类型运算符

typeof 运算符

typeof 是一元运算符,返回操作数的数据类型。

1
2
var num = 12
console.log(typeof num) // 输出结果: number

输出结果:

1
number

instanceof 运算符

instanceof 运算符用于判断对象是否为指定的类型。

其他运算符

负号运算符(-)

负号运算符用于更改操作数的符号。

1
2
3
4
var x: number = 4
var y = -x
console.log("x 值为: ", x) // 输出结果 4
console.log("y 值为: ", y) // 输出结果 -4

输出结果:

1
2
x 值为:  4
y 值为: -4

字符串运算符:连接运算符(+)

+ 运算符可以拼接两个字符串。

1
2
var msg: string = "RUNOOB" + ".COM"
console.log(msg)

输出结果:

1
RUNOOB.COM

条件语句

条件语句用于基于不同的条件来执行不同的动作。TypeScript 条件语句是通过一条或多条语句的执行结果(truefalse)来决定执行的代码块。

决策流程

通常在写代码时,总是需要为不同的决定来执行不同的动作,可以在代码中使用条件语句来完成该任务。在 TypeScript 中,可使用以下条件语句:

  • if 语句:只有当指定条件为 true 时,使用该语句来执行代码。
  • if…else 语句:当条件为 true 时执行代码,当条件为 false 时执行其他代码。
  • if…else if…else 语句:使用该语句来选择多个代码块之一来执行。
  • switch 语句:使用该语句来选择多个代码块之一来执行。

if 语句

TypeScript if 语句由一个布尔表达式后跟一个或多个语句组成。

语法

1
2
3
if (boolean_expression) {
// 在布尔表达式 boolean_expression 为 true 执行
}

如果布尔表达式 boolean_expressiontrue,则 if 语句内的代码块将被执行。如果布尔表达式为 false,则 if 语句结束后的第一组代码(闭括号后)将被执行。

if 语句流程

实例

1
2
3
4
var num: number = 5
if (num > 0) {
console.log("数字是正数")
}

编译以上代码得到如下 JavaScript 代码:

1
2
3
4
var num = 5
if (num > 0) {
console.log("数字是正数")
}

执行以上代码,输出结果为:

1
数字是正数

if…else 语句

一个 if 语句后可跟一个可选的 else 语句,else 语句在布尔表达式为 false 时执行。

语法

1
2
3
4
5
if (boolean_expression) {
// 在布尔表达式 boolean_expression 为 true 执行
} else {
// 在布尔表达式 boolean_expression 为 false 执行
}

如果布尔表达式为 true,则执行 if 块内的代码;如果布尔表达式为 false,则执行 else 块内的代码。

if-else 流程

实例

1
2
3
4
5
6
var num: number = 12
if (num % 2 == 0) {
console.log("偶数")
} else {
console.log("奇数")
}

编译后得到的 JavaScript 代码:

1
2
3
4
5
6
var num = 12
if (num % 2 == 0) {
console.log("偶数")
} else {
console.log("奇数")
}

输出结果:

1
偶数

if…else if…else 语句

if...else if...else 语句在执行多个判断条件的时候很有用。

语法

1
2
3
4
5
6
7
8
9
if (boolean_expression_1) {
// 在布尔表达式 1 为 true 执行
} else if (boolean_expression_2) {
// 在布尔表达式 2 为 true 执行
} else if (boolean_expression_3) {
// 在布尔表达式 3 为 true 执行
} else {
// 布尔表达式的条件都为 false 时执行
}

需要注意以下几点:

  • 一个 if 判断语句可以有 0 或 1 个 else 语句,它必须放在 else if 语句后面。
  • 一个 if 判断语句可以有 0 或多个 else if,这些语句必须放在 else 之前。
  • 一旦执行了某个 else if 内的代码,后面的 else ifelse 将不再执行。

实例

1
2
3
4
5
6
7
8
var num: number = 2
if (num > 0) {
console.log(num + " 是正数")
} else if (num < 0) {
console.log(num + " 是负数")
} else {
console.log(num + " 不是正数也不是负数")
}

编译后得到的 JavaScript 代码:

1
2
3
4
5
6
7
8
var num = 2
if (num > 0) {
console.log(num + " 是正数")
} else if (num < 0) {
console.log(num + " 是负数")
} else {
console.log(num + " 不是正数也不是负数")
}

输出结果:

1
2 是正数

switch…case 语句

一个 switch 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case,且被测试的变量会对每个 case 进行检查。

语法

1
2
3
4
5
6
7
8
9
10
11
switch (expression) {
case constant-expression:
statement(s)
break // 可选的
case constant-expression:
statement(s)
break // 可选的
// 您可以有任意数量的 case 语句
default: // 可选的
statement(s)
}

switch 语句必须遵循下面的规则:

  • switch 语句中的 expression 是一个要被比较的表达式,可以是任何类型,包括基本数据类型(如 numberstringboolean)、对象类型(如 objectArrayMap)以及自定义类型(如 classinterfaceenum)等。
  • 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号。
  • caseconstant-expression 必须与 switch 中的变量 expression 具有相同或兼容的数据类型。
  • 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止。
  • 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
  • 不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会继续后续的 case,直到遇到 break 为止。
  • 一个 switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default 关键字表示当表达式的值与所有 case 值都不匹配时执行的代码块。default case 中的 break 语句不是必需的。

switch 流程

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var grade: string = "A"
switch (grade) {
case "A": {
console.log("优")
break
}
case "B": {
console.log("良")
break
}
case "C": {
console.log("及格")
break
}
case "D": {
console.log("不及格")
break
}
default: {
console.log("非法输入")
break
}
}

编译后得到的 JavaScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var grade = "A"
switch (grade) {
case "A": {
console.log("优")
break
}
case "B": {
console.log("良")
break
}
case "C": {
console.log("及格")
break
}
case "D": {
console.log("不及格")
break
}
default: {
console.log("非法输入")
break
}
}

输出结果:

1

循环

有的时候,我们可能需要多次执行同一块代码。一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。编程语言提供了更为复杂执行路径的多种控制结构,循环语句允许我们多次执行一个语句或语句组。

循环概览

for 循环

TypeScript for 循环用于多次执行一个语句序列,简化管理循环变量的代码。

语法

1
2
3
for (init; condition; increment) {
statement(s)
}

for 循环的控制流程解析:

  1. init 会首先被执行,且只会执行一次。这一步允许你声明并初始化任何循环控制变量。你也可以不在这里写任何语句,只要有一个分号出现即可。
  2. 接下来,会判断 condition。如果为 true,则执行循环主体;如果为 false,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
  3. 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许你更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
  4. 条件再次被判断。如果为 true,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为 false 时,for 循环终止。

其中 statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。condition 可以是任意的表达式,当条件为 true 时执行循环,当条件为 false 时退出循环。

for 循环流程

实例

以下实例计算 5 的阶乘,for 循环生成从 5 到 1 的数字,并计算每次循环数字的乘积。

1
2
3
4
5
6
7
var num: number = 5
var i: number
var factorial = 1
for (i = num; i >= 1; i--) {
factorial *= i
}
console.log(factorial)

编译后得到的 JavaScript 代码:

1
2
3
4
5
6
7
var num = 5
var i
var factorial = 1
for (i = num; i >= 1; i--) {
factorial *= i
}
console.log(factorial)

输出结果:

1
120

for…in 循环

for...in 语句用于一组值的集合或列表进行迭代输出。

语法

1
2
3
for (var val in list) {
// 语句
}

val 需要为 stringany 类型。

实例

1
2
3
4
5
var j: any
var n: any = "a b c"
for (j in n) {
console.log(n[j])
}

编译后的 JavaScript 代码:

1
2
3
4
5
var j
var n = "a b c"
for (j in n) {
console.log(n[j])
}

输出结果:

1
2
3
a
b
c

for…of、forEach、every 和 some 循环

此外,TypeScript 还支持 for...offorEacheverysome 循环。for...of 语句创建一个循环来迭代可迭代的对象,在 ES6 中引入的 for...of 循环用于替代 for...inforEach(),并支持新的迭代协议。for...of 允许你遍历 Arrays(数组)、Strings(字符串)、Maps(映射)、Sets(集合)等可迭代的数据结构。

TypeScript for…of 循环

1
2
3
4
let someArray = [1, "string", false]
for (let entry of someArray) {
console.log(entry) // 1, "string", false
}

forEacheverysome 是 JavaScript 的循环语法,TypeScript 作为 JavaScript 的语法超集,当然默认也是支持的。因为 forEach 在 iteration 中是无法返回的,所以可以使用 everysome 来取代 forEach

TypeScript forEach 循环

1
2
3
4
5
6
let list = [4, 5, 6]
list.forEach((val, idx, array) => {
// val: 当前值
// idx:当前 index
// array: Array
})

TypeScript every 循环

1
2
3
4
5
6
7
8
let list = [4, 5, 6]
list.every((val, idx, array) => {
// val: 当前值
// idx:当前 index
// array: Array
return true // Continues
// Return false will quit the iteration
})

while 循环

while 语句在给定条件为 true 时,重复执行语句或语句组。循环主体执行之前会先测试条件。

语法

1
2
3
while (condition) {
statement(s)
}

statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。condition 可以是任意的表达式,当条件为 true 时执行循环;当条件为 false 时,程序流将退出循环。

while 循环流程

while 循环的关键点是循环可能一次都不会执行。当条件为 false 时,会跳过循环主体,直接执行紧接着 while 循环的下一条语句。

实例

1
2
3
4
5
6
7
var num: number = 5
var factorial: number = 1
while (num >= 1) {
factorial = factorial * num
num--
}
console.log("5 的阶乘为:" + factorial)

编译后的 JavaScript 代码:

1
2
3
4
5
6
7
var num = 5
var factorial = 1
while (num >= 1) {
factorial = factorial * num
num--
}
console.log("5 的阶乘为:" + factorial)

输出结果:

1
5 的阶乘为:120

do…while 循环

不像 forwhile 循环它们是在循环头部测试循环条件,do...while 循环是在循环的尾部检查它的条件。

语法

1
2
3
do {
statement(s)
} while (condition)

请注意,条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。如果条件为 true,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为 false 为止。

do-while 流程

实例

1
2
3
4
5
var n: number = 10
do {
console.log(n)
n--
} while (n >= 0)

编译后的 JavaScript 代码:

1
2
3
4
5
var n = 10
do {
console.log(n)
n--
} while (n >= 0)

输出结果:

1
2
3
4
5
6
7
8
9
10
11
10
9
8
7
6
5
4
3
2
1
0

break 语句

break 语句有以下两种用法:

  1. break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
  2. 它可用于终止 switch 语句中的一个 case

如果你使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。

语法

1
break

break 流程

实例

1
2
3
4
5
6
7
8
9
var i: number = 1
while (i <= 10) {
if (i % 5 == 0) {
console.log("在 1~10 之间第一个被 5 整除的数为 : " + i)
break // 找到一个后退出循环
}
i++
}
// 输出 5 然后程序执行结束

编译后的 JavaScript 代码:

1
2
3
4
5
6
7
8
9
var i = 1
while (i <= 10) {
if (i % 5 == 0) {
console.log("在 1~10 之间第一个被 5 整除的数为 : " + i)
break // 找到一个后退出循环
}
i++
}
// 输出 5 然后程序执行结束

输出结果:

1
1~10 之间第一个被 5 整除的数为 : 5

continue 语句

continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。

对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 whiledo...while 循环,continue 语句重新执行条件判断语句。

语法

1
continue

continue 流程

实例

1
2
3
4
5
6
7
8
9
var num: number = 0
var count: number = 0
for (num = 0; num <= 20; num++) {
if (num % 2 == 0) {
continue
}
count++
}
console.log("0 ~20 之间的奇数个数为: " + count) // 输出 10

编译后的 JavaScript 代码:

1
2
3
4
5
6
7
8
9
var num = 0
var count = 0
for (num = 0; num <= 20; num++) {
if (num % 2 == 0) {
continue
}
count++
}
console.log("0 ~20 之间的奇数个数为: " + count) // 输出 10

输出结果:

1
0 ~20 之间的奇数个数为: 10

无限循环

无限循环就是一直在运行不会停止的循环。forwhile 循环都可以创建无限循环。

for 创建无限循环语法格式:

1
2
3
for (;;) {
// 语句
}

实例:

1
2
3
for (;;) {
console.log("这段代码会不停的执行")
}

while 创建无限循环语法格式:

1
2
3
while (true) {
// 语句
}

实例:

1
2
3
while (true) {
console.log("这段代码会不停的执行")
}

迭代器与生成器

迭代器和生成器是处理集合的关键模式。迭代器提供了一个统一的 next() 方法用于遍历数据,生成器则是一种特殊的函数,能够在执行过程中暂停并返回值,让处理大数据流、无限序列等变得更加简单。

为什么需要迭代器与生成器

在处理集合数据时,我们常常需要遍历数组、对象等。迭代器提供了统一的、可定制的遍历接口;生成器则提供了一种简洁的方式来创建迭代器——使用可以暂停和恢复执行的函数。

  • 迭代器是一个对象,它提供 next() 方法用于遍历数据。
  • 生成器是一种特殊的函数,可以在执行过程中暂停并返回一个值。

可迭代协议(Iterable Protocol)

实现了 Symbol.iterator 的对象可以通过 for...of 来遍历。数组和字符串都内置实现了 Symbol.iterator 方法,所以可以直接使用 for...of 遍历。

1
2
3
4
5
6
7
8
9
10
11
// 数组默认可迭代
var arr = [1, 2, 3]
for (var item of arr) {
console.log("数组元素: " + item)
}

// 字符串默认可迭代
var str = "hello"
for (var char of str) {
console.log("字符: " + char)
}

输出结果:

1
2
3
4
5
6
7
8
数组元素: 1
数组元素: 2
数组元素: 3
字符: h
字符: e
字符: l
字符: l
字符: o

自定义可迭代对象

通过实现 Symbol.iterator,可以让一个普通对象变得可遍历。迭代器协议要求迭代器必须有一个 next() 方法,返回 { done: boolean, value: any } 格式的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var range = {
from: 1,
to: 5,
[Symbol.iterator]: function () {
return {
current: this.from,
last: this.to,
next: function () {
if (this.current <= this.last) {
return { done: false, value: this.current++ }
}
return { done: true, value: undefined }
}
}
}
}

for (var num of range) {
console.log("范围: " + num)
}

输出结果:

1
2
3
4
5
范围: 1
范围: 2
范围: 3
范围: 4
范围: 5

生成器函数

使用 function* 语法定义生成器函数,配合 yield 可以暂停执行并返回值。生成器函数会返回一个迭代器,每次调用 next() 都会执行到下一个 yield 语句。

1
2
3
4
5
6
7
8
9
10
11
function* numberGenerator() {
yield 1
yield 2
yield 3
}

var gen = numberGenerator()
console.log("第一个: " + gen.next().value)
console.log("第二个: " + gen.next().value)
console.log("第三个: " + gen.next().value)
console.log("完成: " + gen.next().done)

输出结果:

1
2
3
4
第一个: 1
第二个: 2
第三个: 3
完成: true

无限生成器

生成器可以借助惰性求值产生无限序列,而不会消耗无限内存。生成器的最大优势是惰性求值——只有在调用 next() 时才会计算下一个值,非常适合处理无限序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function* infiniteNumbers() {
var n = 1
while (true) {
yield n++
}
}

var gen = infiniteNumbers()
console.log("第1个: " + gen.next().value)
console.log("第2个: " + gen.next().value)
console.log("第3个: " + gen.next().value)

var nums: number[] = []
var iter = infiniteNumbers()
for (var i = 0; i < 5; i++) {
nums.push(iter.next().value)
}
console.log("前5个: " + nums)

输出结果:

1
2
3
4
1: 1
2: 2
3: 3
5: 1,2,3,4,5

委托生成器

使用 yield* 可以将生成操作委托给另一个生成器或可迭代对象。yield* 可以组合多个生成器或可迭代对象,非常适合构建可复用的数据流。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function* gen1() {
yield 1
yield 2
}

function* gen2() {
yield 3
yield 4
}

function* combined() {
yield* gen1()
yield* gen2()
}

for (var num of combined()) {
console.log("值: " + num)
}

输出结果:

1
2
3
4
值: 1
值: 2
值: 3
值: 4

TypeScript 生成器类型

在 TypeScript 中,生成器可以使用 Generator 类型进行标注。Generator<T, R, N> 表示:

  • Tyield 返回值的类型。
  • R 是生成器最终返回的类型。
  • Nnext() 方法接收参数的类型。
1
2
3
4
5
6
7
8
9
function* idGenerator(): Generator<number, void, unknown> {
var i = 1
while (i <= 3) {
yield i++
}
}

var gen = idGenerator()
console.log(Array.from(gen))

输出结果:

1
[ 1, 2, 3 ]

迭代器与生成器要点

  • 迭代器协议:实现 Symbol.iterator,返回一个带 next() 方法的对象。
  • 生成器语法:使用 function* 而不是 function
  • yield 关键字:暂停执行并返回一个值。
  • 惰性求值:生成器按需计算下一个值。

最佳实践:在需要遍历自定义对象、处理大数据流、创建无限序列或需要暂停/恢复的场景下,优先考虑使用迭代器与生成器。可迭代对象实现 Symbol.iterator 接口,生成器使用 function*yield 创建,委托则使用 yield* 组合多个生成器。