TypeScript防脱发级入门——TS中的类

共 4978字,需浏览 10分钟

 ·

2022-01-12 13:51


前端猎手
 链接每一位开发者,让编程更有趣儿!
关注

嗨!大家好!我是法医,一只治疗系前端码猿🐒,与代码对话,倾听它们心底的呼声,期待着大家的点赞👍与关注➕。

1. 面向对象的概述

说到类就不得不说面向对象了,这是因为TS为前端面向对象的开发带来了契机,由于JS没有类型系统,如果使用面向对象方式开发会产生大量的接口(不是指TS中的接口,而是指函数或方法),而大量的接口会导致接口调用复杂度增加,这种复杂度必须通过严格的类型检查来避免错误,如果没有严格的类型检查,那么我们在调用过程中全凭记忆力,在写代码的过程中心都是悬着的😩,没有丝毫安全感可言🤷‍♂️。也正是因为如此,JS语言并不适合大型项目的开发,这是由JS本身特性决定的——解释型和弱类型

TS带来了完整的类型系统,因此开发复杂应用时,无论接口数量有多少,都可以获得完整的类型检查,并且这种检查是具有强约束力的

面向对象这个词已经出来很久了,据说是Alan Kay提出来的,关于谁是面向对象之父也是有争议的,至于是谁,我想不用过多care,面向对象中有许多成熟的模式,能处理各种复杂问题,毕竟在大型应用复杂领域积累了非常多的经验,既然TS为前端面向对象的开发带来了契机,而前端开发也日益复杂,所以前端跟面向对象的结合也是自然而然的事情

什么是面向对象?

面向对象:object-oriented,简称OO,它是一种编程思想,它提出一切以划分对象为出发点思考程序。当然也有其它的编程思想。比如说:面向过程函数式编程面向过程是以功能流程为思考切入点的,不适用大型项目开发,而函数式编程是以数学运算为思考切入点的

2. 类的继承

继承可以描述类与类之间的关系,比如说:人是一个类,男人也是一个类,男人是人,则人和男人可以形成继承关系

如果A和B都是类,并且可以描述为A是B,则A和B形成继承关系,我们把B称为父类A称为子类,当然还有其它一些说法:

  • B是父类,A是子类
  • B派生A,A继承自B
  • B是A的基类,A是B的派生类

如果在书中或者文章中看到不同的说法不要慌🤞,它们表示同一个意思。继承的好处在于子类会拥有父类所有的成员,这样就可以减少很多重复代码

2.1 成员的重写

📢 重写(override):无论是属性还是方法,子类都可以重写父类的相应成员,但需要注意的是子类不能改变父类成员的类型,类型必须匹配

举个例子🌰:子类重写父类的属性

export class Person{
    eyes:number = 0
}
export class Man extends Person{
    eyes:number = 2
    eyes:string = "2" //报错,子类不能修改父类的成员类型,父类是什么类型,子类必须是什么类型
}

const m = new Man();
console.log(m.eyes);//2

举个例子🌰:子类重写父类的方法

export class Person{
    eyes:number = 0
    sayHello(){
        console.log("你好,世界");
        
    }
}
export class Man extends Person{
    eyes:number = 2
    sayHello(){
        console.log("我是男人,我真帅");      
    }
}

const m = new Man();
m.sayHello();//我是男人,我真帅

2.2 this指向问题

📢 注意this关键字:在继承关系中,this的指向是动态的,它是根据具体的调用者来确定this指向

举个例子🌰:this关键字的指向

export class Person{
    name:string = "上帝"
    sayHello(){
        console.log(`你好,我叫${this.name}`);
        
    }
}
export class Man extends Person{
    name:string = "仵法医"
    sayHello(){
        console.log(`你好,我叫${this.name}`);
        
    }
}
const m = new Man();
m.sayHello();//由于这里是 m 调用的,它指向的是Man这个类,所以输出: 你好,我叫仵法医

2.3 super关键字

当我们需要在子类中调用父类的方法时,可以使用super关键字

举个例子🌰:super关键字

export class Person {
    name: string = "上帝"
    sayHello() {
        console.log(`你好,我叫${this.name}`);

    }
}
export class Man extends Person {
    name: string = "仵法医"
    test() {     
        super.sayHello();//你好,我叫仵法医
        this.sayHello();//你好,我叫仵法医
    }
}
const m = new Man();
m.test();

我想大家也看到了,当使用super关键字调用父类函数sayHello的时候,superthis的效果是一样的,但它是有一个前提的,就是子类没有重写父类sayHello函数的前提下是一样的,只有子类重写父类函数的时候,superthis才有差别

举个例子🌰:重写sayHello函数,再看super关键字

export class Person {
    name: string = "上帝"
    sayHello() {
        console.log(`你好,我叫${this.name}`);

    }
}
export class Man extends Person {
    name: string = "仵法医"
    sayHello() {
        console.log(`我是帅哥`);
    }
    test() {     
        super.sayHello();//你好,我叫仵法医
        this.sayHello();//我是帅哥
    }
}
const m = new Man();
m.test();

2.4 继承的特性

  • 单根性:指子类只能继承一个父类,不能同时继承多个父类,如果想继承多个父类,混入mixin了解一下

  • 传递性:A继承B,C继承A,那么C同时拥有A和B的成员

3. 抽象类

3.1 为什么需要抽象类

📢 抽象类(abstract)在JS中是没有的,它是TS提出来的,有时候,某个类只表示抽象的概念,主要用于提取子类共有的成员,而不能直接创建它的对象,这时该类可以作为抽象类。只要给类前加上abstract就可以表示抽象类,抽象类不可以创建对象

3.2 抽象父类

举个例子🌰:抽象父类 Person,表示人

abstract class Person {
    
}
class Man extends Person {
    
}
class Woman extends Person{

}
const m = new Man();
const w = new Woman();

3.3 抽象成员

📢 在父类中,可能知道有些成员是必须要存在的,比如说一个人的名字,每个人都有名字,但是我们没有办法在父类中直接书写具体叫什么名,只能在子类对象中才能清楚知道,因此,需要一种强约束,让继承该父类的子类必须实现该成员

需要注意的是,只有在抽象类中,才可以有抽象成员,这些抽象成员必须在子类中时实现,必须的必😛

举个例子🌰:抽象成员,子类实现

abstract class Person {//抽象类
    abstract readonly name: string;//抽象成员
}
/**
 * playBoy 表示花花公子
 */

class playBoy extends Person {
   readonly name: string = "老王";//子类实现抽象成员,第一种方式
}
/**
 * prettyWoman 表示美丽的女人
 */

class prettyWoman extends Person {
    readonly name: string;
    constructor() {
        super()
        this.name = "翠花";//子类实现抽象成员,第二种方式
    }
}
/**
 * twoTimer 表示爱情不专一的人
 */

class twoTimer extends Person {
    //这里没有写 set 访问器,所以本身就是只读的,所以可以不用 readonly,也没法用
    get name(): string {
        return "王小贱";//子类实现抽象成员,第三种方式
    }
}
const pB = new playBoy();
const pW = new prettyWoman();
const tT = new twoTimer();
console.log(pB.name,pW.name,tT.name);//老王 翠花 王小贱

4. 静态成员

4.1 什么是静态成员

📢 静态成员就是附着在类上的成员,成员包括属性和方法,如果在JS当中,我们可以说附着在构造函数上的成员。使用static修饰的成员称作静态成员,静态成员也称作非实例成员,它是属于某个类的,而实例成员也叫对象成员,它是属于某个类的对象

举个例子🌰:

class Person {
    name: string = "前端猎手"
    age: number = 18
    static sayHello(say:string){
        console.log(`我想说${say}`);       
    } 
}
const res1 = Person.sayHello("你好,世界!");//静态方法必须通过类调用                                                                                                                                                                                                                                     
console.log(res1);//我想说你好,世界!

const res2 = new Person();//实例成员必须通过实例对象调用
console.log(res2.age,res2.name);//18 翠花

4.2 静态方法中的this

📢 静态方法中的this指向当前类,而实例方法中的this指向当前对象

5. 索引器

对象[值],或者叫做成员表达式,在ts中,默认情况下,不会对索引器(成员表达式做严格的类型检查),使用配置noImplicitAny开启对隐式any的检查。隐式any:ts根据实际情况推导出的any类型

TS中索引器的作用

  • 在严格的检查下,可以实现为类动态增加成员
  • 可以实现动态操作类成员

在js中,所有成员名本质上,都是字符串,如果使用数字作为成员名,会自动转换为字符串

在ts中,如果某个类中使用了两种类型的索引器,要求两种索引器的值类型必须匹配

最后

很感谢小伙伴看到最后😘,如果您觉得这篇文章有帮助到您的的话不妨关注➕+点赞👍+收藏📌+评论📜,您的支持就是我更新的最大动力。

浏览 26
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报