这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战
枚举
接下来,我们学习 TS 中一个新概念:枚举,首先,我们先来看看这个简单的例子:
let myColor = 'Red';
let yourColor = 'Blue';
function isItRed(color) {
return color === 'Red';
}
isItRed(myColor); // true
isItRed(yourColor); // false
上面这样实现有个缺点,外面的 myColor的 'Red' 和里面的 'Red',无法同步的更新。
这里我们有更好的实现方式,就是使用对象来存储这些字符串。这样的话,我们就可以将对应的字符串替换成对象中的某一项了。
替换完之后的好处,就是我们只需要更改 Colors 对象,就可以同步修改后面的内容。
其实我们根本不关心 Colors.Red 和 Colors.Blue 是什么。只需要它有一个值就行。
const Colors = {
Red: 'Red',
Blue: 'Blue'
}
let myColor = Colors.Red;
let yourColor = Colors.Blue;
function isItRed(color) {
return color === Colors.Red;
}
isItRed(myColor); // true
isItRed(yourColor); // false
其实上面这个就是 TS 中枚举的原型。
enum Colors = {
Red,
Blue,
Green
}
let myColor = Colors.Red;
let yourColor = Colors.Blue;
// 在使用这个方法的时候,我们就需要给这个 color 添加一个它的类型。
function isItRed(color: Colors) {
return color === Colors.Red;
}
isItRed(myColor); // true
isItRed(yourColor); // false
// 它只能接受枚举类型的输入,我们输入一个错误的字符串类型的 'Red',就会报错
// 只能够输入枚举类型里面的某一项值
isItRed('Red');
默认为 0,1,2,我们也可以指定它为一个具体的值,这样的话,后面的项,会根据前面的项递增
enum Colors = {
Red = 1,
Blue,
Green
}
enum Colors = {
Red, // 这一项为 0
Blue = 3, // 往后开始递增
Green // 这一项为 4
}
// 除了赋值数字之外,我们还可以给它赋值字符串或者布尔,这样的话,这个枚举类型的每一项,就是字符串类型
enum Colors = {
Red = 'Red',
Blue = 'Blue',
Green = 'Green'
}
习题-关于下面表达式,运行结果为 false 的是?
enum animal {
name,
weight
}
A. animal.name === 0;
B. typeof animal.name === 'string';
C. typeof animal.weight=== 'number';
D.animal['weight'] === 1
答案:B
解析
根据枚举的特性,枚举成员会被赋值为从 0 开始递增的数字。故错误选项为 B。
资料-常数项和计算所得项
枚举项有两种类型:常数项(constant member)和计算所得项(computed member)。
我们开看一个典型的计算所得项的例子:
enum Color {Red, Green, Blue = "blue".length};
上面的例子中,"blue".length 就是一个计算所得项。
上面的例子不会报错,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错:
enum Color {Red = "red".length, Green, Blue};
// index.ts(1,33): error TS1061: Enum member must have initializer.
// index.ts(1,40): error TS1061: Enum member must have initializer.
下面是常数项和计算所得项的完整定义,部分引用自中文手册 - 枚举:
当满足以下条件时,枚举成员被当作是常数:
不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加 1。但第一个枚举元素是个例外。如果它没有初始化方法,那么它的初始值为 0。
枚举成员使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集,它可以在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:
数字字面量
引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的)如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用
带括号的常数枚举表达式
+, -, ~ 一元运算符应用于常数枚举表达式
+, -, *, /, %, <<, >>, >>>, &, |, ^ 二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为NaN或Infinity,则会在编译阶段报错
所有其它情况的枚举成员被当作是需要计算得出的值。
资料-常数枚举
常数枚举是使用 const enum 定义的枚举类型:
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。
上例的编译结果是:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
假如包含了计算成员,则会在编译阶段报错:
const enum Color {Red, Green, Blue = "blue".length};
// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.