TypeScrip-学习(四)枚举 | Type | never | symbol
枚举
在JavaScript
中是没有枚举的概念的TS帮定义了枚举这个类型,定义通过enum
关键字
数字枚举
1
2
3
4
5
6
7
8
9enum Types{
Red,
Green,
BLue
}
//简单的定义默认为数字枚举,那么什么是数字枚举呢,即:枚举值是数字,如果你不设置默认值,那么每一个组员默认都是从0开始的自增数
console.log(Types.Red);//0
console.log(Types.Green);//1
console.log(Types.BLue);//2增长枚举:细心的我们能发现数字枚举是会
自增
的,那么如果我们给上一个设置了一个默认值,下一个是自动增加1
2
3
4
5
6
7
8enum Types{
Red = 1,
Green,
BLue
}
console.log(Types.Red);//1
console.log(Types.Green);//2
console.log(Types.BLue);//3字符串枚举
字符串枚举的概念很简单。 在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。1
2
3
4
5enum Types{
Red = 'red',
Green = 'green',
BLue = 'blue'
}由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化。 换句话说,如果你正在调试并且必须要读一个数字枚举的运行时的值,这个值通常是很难读的 - 它并不能表达有用的信息,字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。
异构枚举
枚举可以混合字符串和数字成员1
2
3
4enum Types{
No = "No",
Yes = 1,
}
类型别名 type
type
关键字(可以给一个类型定义一个名字)多用于复合类型
1 | //定义类型别名 |
type
和 interface
是有区别的
interface
是定义对象类型的,type
是类型别名,他只是一个别名!!interface
可以继承,type
只能通过 & 交叉类型合并type
可以定义 联合类型 和 可以使用一些操作符interface
不行interface
遇到重名的会合并 type 不行,而且不能重复定义
type高级用法
1 | //右边是否包含左边 |
TS类型层级图
never类型
TypeScript
将使用 never 类型来表示不应该存在的状态(很抽象是不是)
1 | // 返回never的函数必须存在无法达到的终点 |
never 与 void 的差异
1 | //void类型只是没有返回值 但本身不会出错 |
任何类型都不能赋值给
never
类型
symbol类型
symbol
成为了一种新的原生类型,就像number
和string
一样。symbol
类型的值是通过Symbol
构造函数创建的。可以传递参做为唯一标识 只支持 string
和number
类型的参数
Symbol的值是唯一的
1 | const s1 = Symbol(1) |
一般来说
Symbol
是创建唯一值,但是可以调用for
来创建Symbol
,console.log(Symbol.for('key')==Symbol.for('key'))
为true
,因为for是查找Symbol
有没有注册对应的key
值(key为string类型),如果有就返回,如果没有就创建,故是相同的
使用symbol定义的属性,是不能通过如下方式遍历拿到的
1 | const symbol1 = Symbol('hale') |
Symbol.iterator 迭代器 和 生成器 for of
在es6中有iterator
(迭代器)概念,遍历大部分类型迭代器 arr
nodeList
函数的 arguments 对象
set
map
等
1 | var arr:number[] = [1,2,3,4]; |
ES6
规定,默认的 Iterator
接口部署在数据结构的Symbol.iterator
属性,或者说,一个数据结构只要具有Symbol.iterator
属性,就可以认为是可遍历的
象 (Object) 之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。不过,严格地说,对象部署遍历器接口并不是很必要,因为这时对象实际上被当作 Map 结构使用,ES5
没有 Map
结构,而 ES6
原生提供了。下面是es6对应的知识点:
生成器
1
2
3
4
5
6
7
8
9
10
11
12function* getApp() {
yield 'hale'
yield '24'
yield Promise.resolve('你好')
yield 'man'
}
let app = getApp()
console.log(app.next())
console.log(app.next())
console.log(app.next())
console.log(app.next())
console.log(app.next())迭代器利用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let map: Map<any, any> = new Map();
map.set([1, 2, 3], 'hale')
let set = new Set([1, 2, 2, 1, 4, 3, 5, 4])
let arr = [1, 2, 3, 1, 2, 3]
let each = (value: any) => {
let It: any = value[Symbol.iterator]()
let next: any = { done: false }
while (!next.done) {
next = It.next();
if (!next.done) console.log(next.value)
}
}
each(map)
each(arr)
each(set)for of
就是迭代器的语法糖,就是上面内置的each
方法1
2
3
4
5
6
7let map: Map<any, any> = new Map();
map.set([1, 2, 3], 'hale')
let set = new Set([1, 2, 2, 1, 4, 3, 5, 4])
let arr = [1, 2, 3, 1, 2, 3]
for(let value of set){
console.log(value)
}数组的解构
数组的解构或者
[...]
利用的就是迭代器,如果需要数组方法解构对象,可以自己封装1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25let obj = {
currentIndex: 0,
maxIndex: 5,
[Symbol.iterator]() {
return {
currentIndex: this.currentIndex,
maxIndex: this.maxIndex,
next() {
if (this.maxIndex == this.currentIndex) {
return {
value: undefined,
done: true,
}
} else {
return {
value: this.currentIndex++,
done: false,
}
}
}
}
}
}
let ad=[...obj]
console.log(ad) //[ 0, 1, 2, 3, 4 ]注意这是数组的解构原理,对应的解构有自己的原理
以下为这些symbols的列表:
Symbol.hasInstance
方法,会被instanceof运算符调用。构造器对象用来识别一个对象是否是其实例。
Symbol.isConcatSpreadable
布尔值,表示当在一个对象上调用Array.prototype.concat时,这个对象的数组元素是否可展开。
Symbol.iterator
方法,被for-of语句调用。返回对象的默认迭代器。
Symbol.match
方法,被String.prototype.match调用。正则表达式用来匹配字符串。
Symbol.replace
方法,被String.prototype.replace调用。正则表达式用来替换字符串中匹配的子串。
Symbol.search
方法,被String.prototype.search调用。正则表达式返回被匹配部分在字符串中的索引。
Symbol.species
函数值,为一个构造函数。用来创建派生对象。
Symbol.split
方法,被String.prototype.split调用。正则表达式来用分割字符串。
Symbol.toPrimitive
方法,被ToPrimitive抽象操作调用。把对象转换为相应的原始值。
Symbol.toStringTag
方法,被内置方法Object.prototype.toString调用。返回创建对象时默认的字符串描述。
Symbol.unscopables
对象,它自己拥有的属性会被with作用域排除在外。