写点什么

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

作者:法医
  • 2022 年 1 月 12 日
  • 本文字数:3570 字

    阅读完需:约 12 分钟

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

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

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 中,如果某个类中使用了两种类型的索引器,要求两种索引器的值类型必须匹配

最后

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

发布于: 刚刚阅读数: 2
用户头像

法医

关注

公众号@前端猎手 2020.07.17 加入

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

评论

发布
暂无评论
👀TypeScript防脱发级入门——TS中的类