TS的类!


我们知道, JS 是靠原型和原型链来实现面向对象编程的,es6 新增了语法糖 class。

TS 通过 public、private、protected 三个修饰符来增强了 JS 中的类。

在 TS 中,写法和 JS 差不多,只是要定义一些类型而已。

1.基本写法
定义一个Person类,有属性name和方法speak

class Person {
    name: string
    constructor(name: string) {
        this.name = name
    }
    speak() {
        console.log(`${this.name} is speaking`)
    }
}
 
const p1 = new Person('lin')      // 新建实例  
 
p1.name                           // 访问属性和方法
p1.speak()

2.继承
使用extends关键字实现继承,定义一个Student类继承自Person类。

总结: 类和类之间如果要有继承关系,需要使用extends关键字

子类中可以调用父类中的构造函数,使用的是super关键字(包括调用父类中的实例方法,也可以使用super)

子类中可以重写父类的方法

class Student extends Person {
    study() {
        console.log(`${this.name} needs study`)
    }
}
 
const s1 = new Student('lin')

s1.study()
继承之后,Student 类上的实例可以访问 Person 类上的属性和方法。speak和study方法和name方法。

3.super关键字
上例中 Student 类没有定义自己的属性,可以不写 super ,但是如果 Student 类有自己的属性,就要用到 super 关键字来把父类的属性继承过来。

比如,Student 类新增一个 grade(成绩) 属性,就要这么写:

class Student extends Person {
    grade: number
    constructor(name: string,grade:number) {
        super(name)
        this.grade = grade
    }
}
 
const s1 = new Student('lin', 100)

4.多态
子类对父类的方法进行了重写,子类和父类调同一个方法时会不一样。

父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为。

class Student extends Person {
    speak() {
        return `Student ${super.speak()}`
    }
}

TS 中一般对抽象方法实现多态,详细见后文抽象类。

5.public
public,公有的,一个类里默认所有的方法和属性都是 public。

public 可写可不写,不写默认也是 public。

public修饰符,类中成员默认的修饰符,代表的是公共的,任何位置都可以访问类中的成员

class Person {
    public name: string
    public constructor(name: string) {
        this.name = name
    }
    public speak() {
        console.log(`${this.name} is speaking`)
    }
}

6.private
private,私有的,只属于这个类自己,它的实例和继承它的子类都访问不到。

将 Person 类的 name 属性改为 private。

类中的成员如果使用private来修饰,你们外部是无法访问这个成员数据的。

class Person {
    private name: string
    public constructor(name: string) {
        this.name = name
    }
    public speak() {
        console.log(`${this.name} is speaking`)
    }
} 

7.protected
protected 受保护的,继承它的子类可以访问,实例不能访问。

将 Person 类的 name 属性改为 protected。

class Person {
    protected name: string
    public constructor(name: string) {
        this.name = name
    }
    public speak() {
        console.log(`${this.name} is speaking`)
    }
}

8.readonly
首先是一个关键字,对类中的属性成员进行修饰,修饰符后,该属性成员,就不能在外部被随意的修改了。

9.this类型
类的成员方法可以直接返回一个 this,这样就可以很方便地实现链式调用。

1.链式调用

class StudyStep {
  step1() {
    console.log('listen')
    return this
  }
  step2() {
    console.log('write')
    return this
  }
}
 
const s = new StudyStep()
 

s.step1().step2() // 链式调用
2.灵活调用子类父类方法

class StudyStep {
  step1() {
    console.log('listen')
    return this
  }
  step2() {
    console.log('write')
    return this
  }
}
class MyStudyStep extends StudyStep {
  next() {
    console.log('before done, study next!')
    return this   
  }
}
const m = new MyStudyStep()
 

m.step1().next().step2().next() // 父类型和子类型上的方法都可随意调用
这样就保持了父类和子类之间接口调用的连贯性。

10.interface 和 class 的关系
interface 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。

interface 同样可以用来约束 class,要实现约束,需要用到 implements 关键字。

11.implements
implements 是实现的意思,class 实现 interface。

比如手机有播放音乐的功能,可以这么写:

interface MusicInterface {
    playMusic(): void
}
 
class Cellphone implements MusicInterface {
    playMusic() {}
}

12.处理公共的属性和方法
不同的类有一些共同的属性和方法,使用继承很难完成。

比如汽车(Car 类)也有播放音乐的功能,你可以这么做:

用 Car 类继承 Cellphone 类

找一个 Car 类和 Cellphone 类的父类,父类有播放音乐的方法,他们俩继承这个父类

很显然这两种方法都不合常理。

实际上,使用 implements,问题就会迎刃而解。

interface MusicInterface {
    playMusic(): void
}
 
class Car implements MusicInterface {
    playMusic() {}
}
 
class Cellphone implements MusicInterface {
    playMusic() {}
}

再比如,手机还有打电话的功能,就可以这么做,Cellphone 类 implements 两个 interface。

interface MusicInterface {
    playMusic(): void
}
 
interface CallInterface {
    makePhoneCall(): void
}
 
class Cellphone implements MusicInterface, CallInterface {
    playMusic() {}
    makePhoneCall() {}
}

13.约束构造函数和静态属性
使用 implements 只能约束类实例上的属性和方法,要约束构造函数和静态属性,需要这么写。

i

nterface CircleStatic {
    new (radius: number): void
    pi: number
}
 
const Circle:CircleStatic = class Circle {
    static pi: 3.14
    public radius: number
    public constructor(radius: number) {
        this.radius = radius
    }
}

14.存取器
TypeScript支持通过getters和setters来截取对象成员的访问,它能帮助你有效的控制对对象成员的访问。

class Person{
    firstName string= 'A'
    lastName string= 'B'
    get fullName (){
        return this.firstName + '-' +this.lastName
    }
    set fullName (value){
        const names = value.split('-')
        this.firstName = names[0]
        this.lastName = names[1]
    }
}const P = new Person()
console.log(p.fullName)
​
p.firstName ='C'
p.lastName ='D'
console.log(p.fullName)
​
p.fullName = 'E-F'
console.log(p.firstName,p.lastName)

15.抽象类
abstract抽象类作为其他派生类的基类使用,不能被实例化。不同于接口,抽象类可以包含成员的实现细节。abstract 关键字是用于定义抽象类和抽象内部定义抽象方法。

/*
抽象类:
不能创建实例对象,只有实现类才能创建实例对象
可以包含未实现的抽象方法
/

abstract class Animal {
    abstract cry ()
    run(){
        console.log('run()')
    }
 }
 class Dog extents Animal{
    cry(){
        console('Dog cry()')
    }
 }
 const dog = new Dog()
 dog.cry()
 dog.run()
16.类类型
类的类型,类的类型可以通过接口来实现。

//定义一个接口
interface  ifly {
    该方法没有任何的实现
    fly()
}
定义一个类,这个类的类型就是上面定义的接口(实际上也可以理解为,ifly接口约束了当前的这个Person)
class person implements ifly{
    实现接口中的方法
    fly(){
        console.log('我会飞,我是超人')
    }
}
实例化对象
const person = new person()
person.fly()
​
定义一个接口
interface iswim{
    swim()
}定义一个类,这个类的类型是ifly和iswim(当前这个类可以实现多个接口,一个类同时也可以被多个接口进行约束)
class person2 implements ifly,iswim{
    fly(){
        console.log('我会飞,我是超人')
    },
    swim(){
        console.log('我会游泳,我是蛙人')
    }
}

实例化对象

const person2 = new person2()
person2.fly()
person2.swim()
总结:类可以通过接口的方式,来定义当前这个类的类型
类可以实现一个接口,类可以实现多个接口,要注意,接口中的内容都要真正的实现。
​
定义了一个接口,继承其他的多个接口
interface person3 implements imyflyandswim{
    fly(){
        console.log('我会飞3,我是超人')
    },
    swim(){
        console.log('我会游泳3,我是蛙人')
    }
}
const person3 = new person3()
person3.fly()
person,swim()

总结:接口和接口之间叫继承(使用的是extends关键字),类和接口之间叫做实现(使用的是implements)。

TypeScript的修饰符有以下几种: 1. public public是默认修饰符,即不写修饰符时默认为public。public修饰的属性或方法可以在的内部和外部使用。 2. private private修饰的属性或方法只能在的内部使用,无法在的外部使用。 3. protected protected修饰的属性或方法可以在的内部和子中使用,但无法在的外部使用。 4. readonly readonly修饰的属性只能在初始化时或构造函数中赋值,之后就无法再修改。 示例代码: ```typescript class Person { public name: string; // 公共属性 private age: number; // 私有属性 protected gender: string; // 保护属性 readonly id: number; // 只读属性 constructor(name: string, age: number, gender: string, id: number) { this.name = name; this.age = age; this.gender = gender; this.id = id; } public sayHello() { // 公共方法 console.log(`Hello, my name is ${this.name}.`); } private getAge() { // 私有方法 return this.age; } protected getGender() { // 保护方法 return this.gender; } } class Student extends Person { public getGenderAndAge() { console.log(`My gender is ${this.getGender()} and age is ${this.getAge()}.`); } } const person = new Person('Tom', 18, 'male', 1001); console.log(person.name); // Tom // console.log(person.age); // 无法访问 // console.log(person.gender); // 无法访问 // person.id = 1002; // 无法修改 person.sayHello(); // Hello, my name is Tom. const student = new Student('Jerry', 17, 'female', 1002); // console.log(student.age); // 无法访问 // console.log(student.gender); // 无法访问 console.log(student.name); // Jerry console.log(student.id); // 1002 student.getGenderAndAge(); // My gender is female and age is undefined. ``` 在上面的示例代码中,我们定义了一个Person,其中包含了公共属性、私有属性、保护属性、只读属性、公共方法、私有方法和保护方法。这些属性和方法都有不同的修饰符,可以在不同的场景下使用。同时,我们还定义了一个Student,继承自Person,可以访问Person中的保护属性和保护方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值