# 类
ts的类和ES6的类类似,constructor为构造函数,在里面接收默认参数或执行默认函数,属于实例本身。在constructor外的其他方法则相当于定义在原型上。
class Person {
name: string
constructor(name: string) { // 构造函数 实例化的时候触发的方法
this.name = name
}
run():void {
console.log(this.name)
},
eat(food: string):void {
console.log(`${this.name} like eat ${food}`)
}
}
var p = new Person('chang');
p.run(); // chang
p.eat('banana'); // chang like eat banana
# 类的修饰符
类的修饰符主要有public
protected
private
readonly
,默认为public,对类内部的属性或方法进行修饰,以达到约束使用范围。
- public: 公有属性或方法 子类、类外面都可以访问,默认为public
- protected:保护类型 在类、子类里面可以访问,类外部无法访问,实例化后也无法使用
- private: 私有属性或方法 只在类里面可以访问,子类、类外部或实例都无法访问
- readonly:只读属性,无法修改
class Animal {
readonly id: number
public name:string
protected level:number
private age: number
constructor(name:string, level: number, age:number) {
this.name = name
this.level = level
this.age = age
}
eat():void {
console.log(`${this.name}在吃东西`)
}
getAge():void {
console.log(`${this.age}在吃东西`)
}
}
class Cat extends Animal {
constructor(name:string, level: number, age:number) {
super(name, level,age)
}
move():void {
console.log(`${this.name}在玩耍`)
}
getLevel():void {
console.log(this.level)
}
}
var animal = new Animal('动物', 0, 3)
console.log(animal.name) // 动物 在外部访问公有属性
// console.log(animal.level) // 保护类型在外部无法访问
// console.log(animal.age) // 私有类型无法访问
var cat = new Cat('猫', 1, 18)
cat.eat()
cat.move();
cat.getLevel(); // 1 内部获取protected类型
console.log(cat.name) // 猫
// console.log(cat.age) // 私有类型无法访问
// console.log(cat.level) 外部无法访问protected类型
# 参数属性
在类定义一个变量,然后在constructor中接收传入的参数,每次都这样写太麻烦,可以直接在constructor接收参数时定义参数的修饰符来简写。
class Department {
public name:string
protected level:number
private age: number
constructor(name:string, level: number, age:number) {
this.name = name
this.level = level
this.age = age
}
}
// 等同于
class Department1 {
constructor(public name:string, protected level: number, private age:number) {
}
}
# 静态属性、静态方法
类可以直接调用,实例对象无法调用。静态方法的this只能调用类的静态属性。
class Tool {
name: string = 'chang'
static age = 200 // 静态属性
constructor() {}
static getAge() { // 静态方法
console.log(this.age)
}
}
Tool.getAge(); // 200
console.log(Tool.age) // 200
# getter和setter
使用get函数和set函数来对某个属性进行取值和存值,并拦截该属性的存取行为。通过 “.” 操作获取和设置值。
class Phone {
num = 0
// 通过return来取值
get price() {
console.log('价格属性获取成功');
return this.num
}
// 通过传递参数来存值
set price(newValue) {
this.num = newValue
console.log('价格属性设置成功');
}
}
var p = new Phone()
p.price
// 价格属性获取成功
// 0
p.price = 180
// 价格属性设置成功
// 180
console.log(p.price)
// 180
# 类的约束
定义一个接口对类进行约束,使用implements
关键字来定义
interface DogAttr {
food: string
eat(str?:string):void
}
// 类必须要有name和eat
class Dog implements DogAttr {
food:string
constructor(food:string) {
this.food = food
}
eat():void {
console.log(`dog like eat ${food}`)
}
}
var dog = new Dog('狗粮')
dog.eat();
# 继承
子类继承父类的方法和属性,使用 extends
继承后,必须在子类的constructor函数中执行super
后才能继承父类,不执行会报错,并且super必须放在最上面才行。
super的原理就是 prototype.constructor.call
借用父类里的方法和属性。
class Person {
name: string
age: number
constructor(name: string, age: number) { // 构造函数 实例化的时候触发的方法
this.name = name
this.age = age
}
run():void {
console.log(this.name)
}
}
// extends super
class Student extends Person {
// 通过super继承父类的属性和方法
constructor(name: string) {
super(name, 18) // 参数可以子类传入,也直接传
super.run() // 可以使用super直接调用父类的方法或属性
}
learn():void {
console.log(`${this.name}学习中`)
}
}
var stu = new Student('李四')
stu.run();
stu.learn();
# 多态
父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现
class Animal2 {
name: string
constructor(name:string) {
this.name = name
}
eat() {
console.log('吃')
}
}
class Dog extends Animal2 {
constructor(name: string) {
super(name)
}
eat() {
console.log(this.name + '吃骨头')
}
}
class Cat1 extends Animal2 {
constructor(name: string) {
super(name)
}
eat() {
console.log(this.name + '吃鱼')
}
}
# 抽象类
抽象类也叫做基类(鸡肋),抽象类它是提供其他类继承的基类,不能被直接实例化,在抽象类里定义的方法叫抽象方法,抽象方法只能放在抽象类中,让子类必须定义。就像类的接口一样对类进行约束,但抽象类里可以定义其他方法,子类可以直接使用,比接口更高级一点。
用abstract
关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体事项并且必须在派生类中实现
抽象类和抽象方法用来定义标准:比如: Animal3 这个类要求他的子类必须包括eat方法
// 抽象类/基类
abstract class Animal3 {
name:string
constructor(name: string) {
this.name = name
}
jump():void {}
// 定义一个抽象方法,继承他的子类必须实现
abstract eat():any;
}
// var animal = new Animal3('name') // 不能实例化
// 派生类
class Pig extends Animal3 {
constructor(name: any) {
super(name)
}
run() { }
eat():void {
console.log(`${this.name}会吃`)
}
}
var pig = new Pig('猪')
pig.jump();
pig.eat();
pig.run();
# 虚拟DOM
模仿Vue创建和渲染虚拟DOM
// 定义传参options的接口
interface Options {
el: string | HTMLElement
}
// 定义类接口
interface VueCls {
options: Options
init():void
}
// 定义节点的接口
interface Vnode {
tag: string
text?: string
children?: Vnode[]
}
// 创建一个父类,定义一些渲染DOM的方法
class Dom {
// 创建节点
private createElement(el: string) {
return document.createElement(el);
}
// 填充文本
private fillText(el: HTMLElement, text: string | null) {
el.textContent = text
}
// 渲染DOM节点,传入虚拟节点,递归创建DOM,然后返回
protected render(data:Vnode) {
let dom: HTMLElement = this.createElement(data.tag)
if (data.text) this.fillText(dom, data.text)
if (data.children && data.children.length) {
data.children.forEach(item => {
let childDom = this.render(item)
dom.appendChild(childDom)
})
}
return dom
}
}
// 创建一个Vue
class Vue extends Dom implements VueCls {
options: Options
constructor(options: Options) {
super() // 继承父类
this.options = options
// 默认执行方法
this.init()
}
init(): void {
// 定义一个虚拟DOM,然后通过js渲染成真正的DOM
let data:Vnode = {
tag: 'div',
children: [
{
tag: 'p',
text: '我是子节点1'
},
{
tag: 'p',
text: '我是子节点2',
children: [
{
tag: 'span',
text: '我是子节点2-1',
}
]
}
]
}
// 获取渲染成功后的DOM添加到根节点
let dom = this.render(data)
let app = typeof this.options.el === 'string' ? document.querySelector(this.options.el) : this.options.el
app?.appendChild(dom)
}
}
new Vue({
el: '#app'
})