1、class
Ⅰ. 类型约束 implements 继承 extends
构造函数constructor,默认方法或者参数要调用或者接收,在此初始化
class约束关键字 implements
子类调用父类的方法,在类型约束前extends父类;继承父类的子类需要在constructor调用super
Ⅱ. class的修饰符 readonly private protected public
a、readonly 属性只读,不可修改
b、private 只能在类内部调用方法,子类也无法调用父类方法
c、protected 代表定义的变量私有的,只能在内部和继承的子类中访问,不能在外部访问
d、public 默认都为public 外部可以访问
Ⅲ. super
调用父类方法时,须在子类构造函数调用super()
super() 相当于 父类的prototype.constructor.call
可以通过super直接调用父类方法,如:super.render()
Ⅳ. 静态方法
用static定义类或者属性,只能通过类名访问,无法通过this获取
如 Dom.author / Dom.version()
静态方法里this只能获取静态的属性/方法
interface Options {
el: string | HTMLElement
}
interface VueCls {
options: Options,
init(): void
}
interface VNode {
// 标签、文本、子节点
tag: string,
text: string | null,
children: VNode[]
}
// 实现一个虚拟DOM的方法,创建标签方法/标签填充文本/渲染
class Dom {
static author: string;
constructor(name: string) {
}
static version() {
this.author = 'avido';
return `${this.author} 1.0.0.0`
}
private createElement(el: string) {
return document.createElement(el);
}
private setText(el: HTMLElement, text: string | null) {
el.textContent = text;
}
protected render(data:VNode) {
let root = this.createElement(data.tag);
if(data.children && Array.isArray(data.children)) {
data.children.forEach(item => {
let child = this.createElement(item.tag);
this.setText(child,item.text);
root.appendChild(child)
})
} else {
this.setText(root,data.text)
}
return root;
}
public recursionNode() {
// TODO
// 当前只做了子节点递归,应该包括子节点下的其他节点渲染
}
}
let dom = new Dom('123');
dom.recursionNode();
Dom.author;
Dom.version();
// Vue类约束类型为VueCls
// 参数通过constructor接收(即初始化),其他方法才能获取该参数
// constructor函数里关于参数、方法、父类方法初始化非常重要!!!
class Vue extends Dom implements VueCls {
options: Options;
constructor(options: Options) {
super('name');
this.options = options;
this.init();
}
init(): void {
console.log(this.options)
let data:VNode = {
tag: 'div',
text: 'father',
children: [
{
tag: 'div',
text: 'son1',
children: [
{
tag: 'p',
text: 'grandson',
children: []
}
]
},
{
tag: 'div',
text: 'son2',
children: []
}
]
}
// 创建根节点,将生成的根节点添加
let app = typeof this.options.el == 'string' ? document.querySelector(this.options.el) : this.options.el;
app?.appendChild(this.render(data));
}
}
new Vue({
el: '#app'
})
// 总结简单版虚拟dom的实现逻辑
// a、子类声明数据,父类提供创建元素方法,子类调用父类方法
// b、通过多个interface约束对象类型;子类通过extends继承父类
// c、constructor 初始化参数和方法+父类方法
Ⅴ. get set
class Ref {
_value: any;
constructor(value: any) {
this._value = value;
}
get value() {
return this._value + '_1008611';
}
set value(newVal) {
this._value = newVal + '_Avido'
}
}
// 从打印时能看出声明get和set时,_value和value是不一样的
const ref = new Ref('hey');
console.log(ref.value, ref._value)
ref.value = 'Hello'
console.log('newVal',ref.value,ref._value)
2、抽象类(基类)
abstract 所定义的类即抽象类
abstract 定义的方法,只能描述不能实现
抽象类无法被实例化
abstract class Vue_ab {
name: string
constructor(name: string) {
this.name = name;
}
getName(): string {
return this.name;
}
// abstract init() {} // 报错,abstract标记的方法无法实现
abstract init(name: string):void
}
// const vue_ab = new Vue_ab(); // 报错,无法实例化
// 用法:派生类继承抽象类
// 派生类需要实现抽象类描述的方法,如上的init
// 继承抽象类的派生类可以被实例化
class Vue_derive extends Vue_ab {
constructor() {
super('111');
}
init(name: string): void {
}
setName(name: string) {
this.name = name;
}
}
const ab_derive = new Vue_derive();
ab_derive.init('init');
console.log(ab_derive.getName())
ab_derive.setName('Hey You Ok?')
console.log(ab_derive.getName())
3、元组类型
是数组的一种
元组中的元素类型可以是不同的,且数量固定,即我们可以获取它的length
如果方法返回多个值,可以作为元组返回,不需要创建类
const arr_tuple = [1,false];
// arr_tuple[0] = '222'; // 报错,该元组被识别为number和boolean的联合类型
arr_tuple[0] = 666;
arr_tuple.push(111)
// 元组声明类型
const arr_tuple2: [string,number] = ['you',20];
arr_tuple2[0] = 'oo';
const arr_tuple3: readonly [x: boolean, y?:number] = [true];
// arr_tuple3[1] = 123; // 报错,readonly只读
let excel: [string,string,number][] = [
['Bepo','bear',25],
['Leo','man',32]
]
const arr_tuple4: readonly [x: boolean, y:number] = [true,33];
type first_tuple = typeof arr_tuple4[1] // number
type length_tuple = typeof arr_tuple4['length'] // 2
4、枚举类型
TS 通过关键字 enum 定义枚举类型
// Ⅰ. 数字枚举
// 在js中
let obj = {
red: 0,
yellow: 1,
blue: 2
}
enum Color {
// 值不声明,默认从0开始
red,
yellow,
blue
}
console.log(Color.red,Color.yellow,Color.blue);
enum Color2 {
// 递增
red = 1,
yellow,
blue
}
console.log(Color2.red, Color2.yellow, Color2.blue);
// Ⅱ. 字符串枚举
enum Color3 {
red = 'red',
yellow = 'yellow',
blue = 'blue'
}
console.log(Color3.red, Color3.yellow, Color3.blue);
// Ⅲ. 异构枚举(字符串+数字)
enum Color4 {
is,
no = 'no',
// are, // 报错,无法递增
yes = 1,
are
}
// Ⅳ. 接口枚举
enum Type_ENUM {
red = 0,
yellow
}
interface Type_Val {
success: Type_ENUM.red,
fail: Type_ENUM.yellow
}
let type_val: Type_Val = {
// success: 1 // 报错,red值为0
success: 0,
fail: Type_ENUM.yellow
}
console.log(type_val,'type_val')
// Ⅴ. const枚举
// const 会将ts 编译成常量,否则编译成对象
const enum Type_ENUM2 {
success,
fail
}
let code:number = 0;
if(code === Type_ENUM2.success) {
console.log(Type_ENUM2.success)
}
// Ⅵ. 反向映射
// 通过value获取其key值
// 只支持数字类型!!!
enum Type_ENUM3 {
success = 200,
serverError = 500
}
let success:number = Type_ENUM3.success;
let key = Type_ENUM3[success]
console.log(`value---${success}`, `key---${key}`)
查看编译后的js文件,可以看到支持反向映射的原理,是通过value-key形式声明数组。
5、类型推论 类型别名
Ⅰ. 类型推论
声明变量,dan没有定义类型
ts自带类型推论 通过声明的变量及值能自动推断该变量的类型
let type_val2 = [1,2,3];
// type_val2 = ''; // 报错,type_val2 类型为number[]
Ⅱ. 类型别名(type)
type s = string | number[];
let type_str:s = '123';
let type_str2:s = [3,3,3];
// extends 在type中是包含的意思
type type_num = 3 extends number ? 1 : 0;
// let ttt: type_num = 0; // 报错。type为1
let ttt: type_num = 1;
// type 和 interface的区别
// a、interface可以继承 type通过&交叉类型合并
// b、interface重名会合并
// c、type可以定义联合类型、使用一些操作符
6、never 类型
ts使用never类型来表示不应该存在的状态
type Type_never = string & number; // 此时为never类型
function neverFun():never {
throw new Error('error')
}
type Type_talent = 'sing' | 'jump' | 'rap' | 'basketball';
// 应用场景
// 当新增值 'basketball',default会报错,因新增string,且无法赋值给error
// 这种情况我们可以通过报错识别到少了对'basketball'的case语句
function getTalent(value: Type_talent) {
switch(value) {
case 'sing':
break;
case 'jump':
break;
case 'rap':
break;
default:
// 用于场景兜底逻辑
const error:never = value; // 报错
console.log('error-value',error);
break;
}
return
}
7、Symbol 类型
Ⅰ. 定义
支持string number undefined 三种类型
创建各自的内存地址,是唯一的,不会相等
let sy1 = Symbol(1);
let sy2 = Symbol(1);
console.log(sy1,sy2)
console.log(sy1 == sy2); // false
Ⅱ. for
如何让两个symbol值返回true
for会在全局查找key,有则拿来用,无则创建
console.log(Symbol.for('abc') === Symbol.for('abc'))
Ⅲ. 应用场景
用作对象属性的键
let sy_obj = {
name: '111',
// name: '222', // ts报错,js覆盖处理
[sy1]: '111',
[sy2]: '222'
}
console.log(sy_obj)
Ⅳ. 读取对象里的symbol值
// for in 不支持
for(let key in sy_obj) {
console.log(key, 'for in')
}
// Object.keys 不支持
console.log(Object.keys(sy_obj),'Object.keys')
// JSON.stringify 不支持
console.log(JSON.stringify(sy_obj), 'JSON.stringify')
// Object.getOwnPropertyNames 不支持
console.log(Object.getOwnPropertyNames(sy_obj),'Object.getOwnPropertyNames');
// Object.getOwnPropertySymbols 只能获取对象中的symbol类型
console.log(Object.getOwnPropertySymbols(sy_obj),'Object.getOwnPropertySymbols');
// ES6语法 Reflect.ownKeys 获取对象所有属性
console.log(Reflect.ownKeys(sy_obj), 'Reflect.ownKeys')
8、迭代器 生成器
Ⅰ. 生成器 定义
function* gen() {
yield Promise.resolve('avido') // 同步异步
yield '1'
yield '2'
yield '3'
}
const empGen = gen();
// empGen.next();
// 按照顺序调用,和同步异步无关
// done为true,表示后面无生成器可迭代
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())
Ⅱ. Set Map
// Set 支持数字和字符串去重
let set1:Set<number> = new Set([1,1,2,2,3,3]) // 天然去重
console.log(set1,'set1')
// map定义key-value
// 实现将引用类型作为key
let map1:Map<any,string> = new Map();
const map_arr = [0,1]
map1.set(map_arr,'avido')
console.log(map1)
console.log(map1.get(map_arr))
// 伪数组
function args() {
console.log(arguments)
}
// let list = document.querySelectorAll('div') // 伪数组
Ⅲ. 迭代器
如何支持所有数据类型(如Set、Map、伪数组等)的遍历
他们自身已定义迭代器
对象不能使用for of,因为对象身上没有Symbol.iterator
// ① 迭代器的语法糖 for of
// 对象不能使用for of,因为对象身上没有Symbol.iterator
for(let i of map1) {
console.log(i,'for of')
}
// for(let i of {name: ''})
// ② for of 的实现原理
// value[Symbol.iterator]().next().value
const 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(set1)
each(map1)
// ③ 数组的解构原理也是通过Symbol.iterator实现
let [e,f,g] = [3,6,9];
console.log(e,f,g,'[e,f,g]')
let arr_sy = [0,1]
let arr_sy_copy = [...arr_sy]
console.log(arr_sy_copy,'arr_sy_copy')
// ④ 如何使对象支持for of
let obj_iterator = {
max: 4,
current: 0,
[Symbol.iterator]() {
return {
max: this.max,
current: this.current,
next() {
if(this.max === this.current) {
return {
value: undefined,
done: true
}
} else {
return {
value: this.current++,
done: false
}
}
}
}
}
}
for(let i of obj_iterator) {
console.log(i,'obj_iterator')
}
for(let i of [...obj_iterator]) {
console.log(i,'[...obj_iterator]')
}
console.log([...obj_iterator])
for(let i of {...obj_iterator}) {
console.log(i,'{...obj_iterator}')
}
// 对象如何实现解构?
// 创建新变量、枚举属性、属性赋值(Object.keys,Object.getOwnPropertySymbol)