一、const 和 readonly 的区别
1、TypeScript 中不可变量的实现方法有两种:
- 使用 ES6 的 const 关键字声明的值类型
- 被 readonly 修饰的属性
2、TypeScript 中 readonly:
TypeScript 中的只读修饰符,可以声明更加严谨的可读属性。通常在 interface
、 Class
、 type
以及 array
和 tuple
类型中使用它,也可以用来定义一个函数的参数。
3、两者区别:
(1)const
用于变量, readonly
用于属性
(2)const
在运行时检查, readonly
在编译时检查
(3)const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值;
readonly
修饰的属性能确保自身不能修改属性,但是当你把这个属性交给其它并没有这种保证的使用者(允许出于类型兼容性的原因),他们能改变
const foo: { readonly bar: number; } = { bar: 123 }; function iMutateFoo(foo: { bar: number }) { foo.bar = 456; } iMutateFoo(foo); console.log(foo.bar); // 456
(4)const
保证的不是变量的值不得改动,而是变量指向的那个内存地址不得改动,例如使用 const
变量保存的数组,可以使用 push
, pop
等方法。
但是如果使用 ReadonlyArray<number>
声明的数组不能使用 push
, pop
等方法。
二、枚举和常量枚举的区别
1、枚举和常量枚举(const枚举):使用枚举可以清晰地表达意图或创建一组有区别的用例
// 枚举 enum Color { Red, Green, Blue } // 常量枚举 const enum Color { Red, Green, Blue }
2、区别:
(1)枚举会被编译时会编译成一个对象,可以被当作对象使用
(2)const
枚举会在 typescript 编译期间被删除,const
枚举成员在使用的地方会被内联进来,避免额外的性能开销
我们先看下面代码,枚举会被编译成什么:
// 枚举 enum Color { Red, Green, Blue } var sisterAn = Color.Red // 会被编译成 JavaScript 中的 var sisterAn = Color.Red // 即在运行执行时,它将会查找变量 Color 和 Color.Red
我们再看下 常量枚举 会被编译成什么:
// 常量枚举 const enum Color { Red, Green, Blue } var sisterAn = Color.Red // 会被编译成 JavaScript 中的 var sisterAn = 0 // 在运行时已经没有 Color 变量
由此可见,使用 常量枚举 会有更好的性能。
定义的枚举,在经过编译器编译后是一个对象,这个对象我们可以在程序运行时使用,前面有说到。但有时定义枚举可能只是为了让程序可读性更好,而不需要编译后的代码,即不需要编译成对象。typescript中考虑到这种情况,所以加入了 const enum (完全嵌入的枚举)。
三、关于 typescript 中的枚举介绍
1、数字枚举:即枚举里所有属性的值都是数字类型
当枚举里的属性没指定具体值时,默认值是从 0 开始依次排列,你也可以自己指定具体值,剩下的也是依次递增:
enum Colors { Red, Blue = 5, Yellow } console.log(Colors.Red) // 0 console.log(Colors.Blue) // 5 console.log(Colors.Yellow) // 6
数字枚举在定义值的时候,可以是 常量 或者是 计算出来的。
(1)它是枚举的第一个成员且没有初始化,这种情况下它被赋予值0 (如上)
(2)它未初始化器且它之前的枚举成员是一个 数字常量。 这种情况下,当前枚举成员的值为它上一个枚举成员的值加1(如上)
(3)枚举成员使用 常量枚举表达式初始化
A的值是被计算出来的。注意注释部分,如果某个属性的值是计算出来的,那么它后面一位的成员必须要初始化值
const getValue = () => { return 0 } enum List { A = getValue(), B = 2, // 此处必须要初始化值,不然编译不通过 C } console.log(List.A) // 0 console.log(List.B) // 2 console.log(List.C) // 3
2、反向映射
可以通过 Enum[key] 或者 Enum.key 的方式获取到对应的值。typescript 还支持反向映射,即可以通过值来获取键,不过反向映射只支持数字枚举。
enum Status { Success = 200, NotFound = 404, Error = 500 } console.log(Status.Success) // 200 console.log(Status[200]) // Success console.log(Status[Status.Success]) // Success
3、字符串枚举要求每个字段的值都必须是字符串字面量,或者是另外一个字符串枚举成员
enum Str { Str1 = 'this is string one', Str2 = 'this is string two', Str3 = Str1 // 这里引用了Str1的值 }
4、异构枚举:把数字枚举和字符串枚举混用,就形成了异构枚举,这种方式很容易引起混淆,不推荐使用。
5、枚举成员:枚举成员的值不可修改。
Char.a = 6; // Cannot assign to 'a' because it is a read-only property
枚举成员可以分为常量的和需要计算的
(1)const enum(常量枚举):
- 没有设置初始值
- 对已有枚举成员的引用
- 常量的表达式
常量枚举成员会在编译时计算出结果,然后以常量的形式,出现在运行时环境
(2)computed enum(需要计算的枚举成员)
这些枚举成员的值不会在编译阶段计算,而是保留到程序的执行阶段
enum Char { // 常量枚举成员 a, b = Char.a, c = 1 + 3, // 非常量枚举成员 d = Math.random(), e = 'hello'.length } console.log(Char);
6、常量枚举
常量枚举其实就是是在 enum关键字前使用 const 修饰符,常量枚举会在编译阶段被移除
作用:当我们不需要一个对象,而需要对象的值,就可以使用常量枚举,这样就可以避免在编译时生成多余的代码和间接引用
const enum Month { Jan, Feb, Mar } console.log(Month); // ReferenceError: Month is not defined console.log(Month.Jan); //输出0
常量枚举成员在使用的地方被内联进来,且常量枚举不可能有计算成员
const enum Directions { Up, Right, Down, Left, UpRight = 3 + 1, RightDown = Directions.Right + 2, LeftDown = 9, // RightUp = 'hello'.length
// const enum member initializers can only contain literal values and other computed enum values }