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
的时候,super
和this
的效果是一样的,但它是有一个前提的,就是子类没有重写父类sayHello
函数的前提下是一样的,只有子类重写父类函数的时候,super
和this
才有差别
举个例子🌰:重写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中,如果某个类中使用了两种类型的索引器,要求两种索引器的值类型必须匹配
最后
很感谢小伙伴看到最后😘,如果您觉得这篇文章有帮助到您的的话不妨关注➕+点赞👍+收藏📌+评论📜,您的支持就是我更新的最大动力。