阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!
枚举
枚举是对客观事物的归纳与自然语言的抽象。这听起来似乎容易和类混淆,这是正常的。因为在大部分面向对象的语言里,枚举就是类。
我们知道一周有七天 —— Week={monday,Tuesday,...., Sunday}
。假设用枚举来描述这个概念的话就是下面这样:
enum Week {
Monday,
Tuesday,
Sunday,
}
你可能会说用常量也可以表示这个概念。但是,常量无法体现「今天只能是一周中的某一天」—— Today ∈ Week={monday,Tuesday,...., Sunday}
这个概念。
enum Week {
Monday,
Tuesday,
Sunday,
}
function f(today: Week) {
if (today === Week.Monday) {
console.log("today is Monday!");
}
}
// f("happyDay"); ==> type error! string is not Enum
f(Week.Monday);
typescript 中枚举的行为
到目前为止,上述示例代码中的枚举行为都是符合预期的。但是「一切正常」向来不是 javascript 的风格。
在 ts 中,下面这样的代码也可以编译成功。
enum Week {
Monday = "Monday",
Tuesday = "Tuesday",
Sunday = 7,
}
console.log(Week);
console.log(Week["Monday"]); // ===> Monday
// f("day"); ==> type error! string is not Enum
function soo(option: string) {
if (option === Week.Monday) {
console.log("today is Monday!");
}
}
soo(Week.Monday);
function doo(option: {}) {
if (option === Week.Monday) {
console.log("today is Monday!");
}
}
doo(Week);
function foo(option: { Monday: Week.Monday }) {
if (option.Monday === Week.Monday) {
console.log("today is Monday!");
}
}
foo(Week);
只要和真正的面向对象语言中枚举的行为相比较,就能发觉 ts 中枚举的类型检查非常的不严谨。
class Scratch {
public static void main(String[] args) {
test(Week.Monday);
}
public static void test(Week w) {
System.out.println(w.name);
System.out.println(w.code);
if (w.equals(Week.Monday)) {
System.out.println(Week.Monday);
} else if (w.equals(Week.Tuesday)) {
System.out.println(Week.Tuesday);
}
}
enum Week {
Monday("Monday", 001),
Tuesday("Tuesday", 002);
private String name;
private Integer code;
Week(String name, Integer code) {
this.name = name;
this.code = code;
}
@Override
public String toString() {
return "Week{" +
"name='" + name + '\'' +
", code=" + code +
'}';
}
}
}
不严谨就算了,ts 中的数字枚举成员还有「反向映射」这样放飞自我的行为。
enum Week {
Monday = "Monday",
Tuesday = "Tuesday",
Sunday = 7,
}
console.log(Week[7]); // ===> Sunday
typescript 中的枚举是什么
打印 ts 中的枚举会输出一个对象。这个对象的属性由枚举成员的 key 与枚举成员的 value 构成。
enum Week {
Monday = "Monday",
Tuesday = "Tuesday",
Sunday = 7,
}
console.log(Week);
-----------
{ '7': 'Sunday', Monday: 'Monday', Tuesday: 'Tuesday', Sunday: 7 }
要注意的是,数字枚举成员除了生成 key/value 形式的正向映射属性以外,还生成 value/key 的反向映射属性 {'7': 'Sunday'}
;而字符串枚举成员只会生成正向映射的属性。
这些行为,都来源于 ts 将枚举设计为一个 js 对象,再通过立即执行函数和赋值操作符返回等式右边值的特性,创建这个对象的正反映射属性造成的。
var Week;
(function (Week) {
Week["Monday"] = "Monday";
Week["Tuesday"] = "Tuesday";
Week[Week["Sunday"] = 7] = "Sunday";
})(Week || (Week = {}));
既然枚举就是对象,那通过「句点操作符」访问属性就能够获取到枚举成员的 value,于是可以通过 soo 函数的参数类型验证。
function soo(option: string) {
if (option === Week.Monday) {
console.log("today is Monday!");
}
}
soo(Week.Monday);
soo(Week["Tuesday"]);
同时枚举对象还拥有数字枚举成员的反向映射属性,那么实现「反向映射」功能显然是轻而易举。
console.log(Week[7]); // ===> "Sunday"
而那些使用对象作为参数类型的函数,理所应当的可以编译成功。
function doo(option: {}) {
if (option === Week.Monday) {
console.log("today is Monday!");
}
}
doo(Week);
function foo(option: { Monday: Week.Monday; a: "test" }) {
if (option.Monday === Week.Monday) {
console.log("today is Monday!");
}
}
foo(Week);
最后因为枚举就是对象,对象就是函数,函数就是类;所以在 ts 中枚举也是类,是对客观事物的归纳与自然语言的抽象。