今天继续学习 @小满zs 的 TS 课程。
1. never 类型
TS 将 never 类型用来表示不应存在的状态。
// 因为必定抛出异常,所以 error 将不会有返回值
function error(msg: string): never {
throw new Error(msg)
}
// 存在死循环,loop 不会有返回值
function loop(): never {
while(true) { }
}
// 联合类型中,never 会被忽略掉 type A = string | number
type A = number | string | never
-----------应用场景 兜底逻辑处理-------------
type kun = "唱" | "跳" | "rap" | "篮球"
function ikun(val: kun) {
switch(val) {
case "唱":
break
case "跳":
break
case "rap":
break
case "篮球":
break
default:
// 兜底逻辑
let error: never = val
break
}
}
2. Symbol 类型
自ECMAScript 2015起,symbol 成为了一种新的原生类型,就像 number 和 string 一样。
- Symbol 的值是唯一的,内存地址不同
let s1 = Symbol(1) // // key: string | number | undefined
let s2 = Symbol(1) // 唯一的
console.log(s1 == s2); // false
// Symbol.for() 先查找全局 Symbol 有没有注册过这个key,有的话直接拿来用,没有就新注册
let s3 = Symbol.for('q') // key: string
let s4 = Symbol.for('q')
console.log(s3 == s4); // true
- 用作对象属性的 key
let s1 = Symbol(1)
let s2 = Symbol(1)
let obj = {
name: "鱼钓猫",
[s1]: 123, // 索引签名取值
[s2]: 345,
[s3]: "一棵松"
}
console.log('obj', obj) // obj { name: '鱼钓猫', [Symbol(1)]: 123, [Symbol(1)]: 345 }
// 以下方式读不到 Symbol
for(let key in obj) {
console.log(key); // 输出一次 name
}
console.log(Object.keys(obj)); // [ 'name' ]
console.log(Object.getOwnPropertyNames(obj)); // [ 'name' ]
// 可以通过一下方式取到 Symbol
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(1), Symbol(1) ]
console.log(Reflect.ownKeys(obj)); // [ 'name', Symbol(1), Symbol(1) ]
3. 生成器
- function 后跟 *
- yield关键字 后跟返回值,可以同步也可以异步
- next() 进行迭代,返回一个对象,done 为 false 表示继续迭代,为 true 表示迭代完毕。
function* gen() {
yield Promise.resolve("鱼钓猫");
yield "小鱼干";
yield true;
yield { name: "一棵松" };
}
const mm = gen()
console.log(mm.next()); // { value: Promise { '鱼钓猫' }, done: false }
console.log(mm.next()); // { value: '小鱼干', done: false }
console.log(mm.next()); // { value: true, done: false }
console.log(mm.next()); // { value: { name: '一棵松' }, done: false }
console.log(mm.next()); // { value: undefined, done: true }
4. 迭代器
4.1 Symbol.iterator
伪数组都包含 Symbol.iterator,可以通过它进行迭代遍历。
// 这些是一些伪数组,都包含 Symbol.iterator
let set: Set<number> = new Set([1, 1, 2, 3, 3])
let map: Map<any, any> = new Map()
map.set('name', "鱼钓猫的小鱼干")
function args() {
console.log(arguments);
}
let list = document.querySelectorAll('div')
function each(data: any) {
// 调用迭代器方法
let Ite = data[Symbol.iterator]()
let next:any = { done: false }
while(!next.done) {
next = Ite.next()
if(!next.done) console.log(next.value);
}
}
4.2 Symbol.iterator 语法糖 for of
- for of 和上面的 each 方法效果一样
- for of 不能遍历对象,因为对象上没有 Symbol.iterator
for(let val of set) {
console.log(val);
}
for(let val of map) {
console.log(val);
}
// erroe 类型“{ current: number; max: number; }”必须具有返回迭代器的 "[Symbol.iterator]()" 方法。
for(let val of obj) {
console.log(val);
}
4.3 实现对象的 for of 方法
- 数组结构调用的是 Symbol.iterator,对象不是
let obj = {
current: 0,
max: 5,
// 手动实现对象的 Symbol.iterator
[Symbol.iterator]() {
return {
current: this.current,
max: this.max,
next() {
if(this.current == this.max) { // 迭代结合
return {
value: undefined,
done: true
}
} else {
return {
value: this.current++,
done: false
}
}
}
}
}
}
for(let val of obj) {
console.log(val); // 0 1 2 3 4
}
console.log([...obj]); // [ 0, 1, 2, 3, 4 ]
console.log({...obj}); // { current: 0, max: 5, [Symbol(Symbol.iterator)]: [Function: [Symbol.iterator]] }