这里不会赘述JS中的类的用法,而是单刀直入,直接来TS中的类的用法。
先提一嘴,JS中的类有私有属性,在属性名之前使用#
表示。私有属性只能在类的内部使用。
class Person {
#name = 'clz'
get val() {
return this.#name
}
}
const person = new Person()
console.log(person.val)
有学过其它语言的可能就会用的有点不太习惯,因为很多语言(指本人课程教的,C++、Java)使用的访问修饰符是public
、private
、protected
。而TS可以使用这三种访问修饰符。
public
:修饰的属性和方法是公有的,可以在任何地方被访问。默认都是public
private
:私有的,只能在声明该属性的类中访问,即也不能被子类访问protected
:受保护的,和private
类似,不过,能被子类访问修饰的属性和方法是公有的,可以在任何地方被访问。
实例:
class Person {
public name;
public constructor(name) {
this.name = name
}
}
class Student extends Person {
public grade;
public constructor(name, grade) {
super(name)
console.log(this.name)
this.grade = grade
}
}
const student = new Student('czh', 3) // czh
const person = new Person('clz')
console.log(person.name) // clz
只能在声明该属性的类中访问,即也不能被子类访问。
实例:把上面的例子中,name
的修饰符变成private
即可。
和private
类似,不过,能被子类访问
访问修饰符和readonly
修饰符能够直接使用在构造函数的参数中。相当于在类中定义该属性的同时赋值。只读属性的用法在对象那一节已经介绍过了。
原版本:
class Person {
public name;
public constructor(name) {
this.name = name
}
}
使用参数属性的简洁版:
class Person {
public constructor(public name) { }
}
另外,如果需要同时使用访问修饰符和readonly
修饰符的话,访问修饰符要在readonly
修饰符之前,如public readonly name
。
abstract
用于定义抽象类和其中的抽象方法。对一个学过Java的人来说,就是面向对象这一块,TS和Java感觉上就是一样的。
抽象类主要是一些没有足够信息来描绘一个具体的对象的类。所以抽象类必须被继承获取足够信息,才能被使用。抽象类不能被实例化对象,但是类的其他功能依然存在。
抽象类的使用:
abstract class Person {
public constructor(public name) { }
}
class Student extends Person {
public grade;
public constructor(name, grade) {
super(name)
this.grade = grade
}
}
const student = new Student('clz', 3)
console.log(student) // Student {name: 'clz', grade: 3}
抽象类还可以有抽象方法,抽象方法只能出现在抽象类中,子类必须实现抽象方法
abstract class Person {
public constructor(public name) { }
public abstract listen()
}
class Student extends Person {
public grade;
public constructor(name, grade) {
super(name)
this.grade = grade
}
// public listen() {
// console.log('Kylee-大好きなのに')
// }
}
const student = new Student('clz', 3)
student.listen() // Kylee-大好きなのに
class Person {
public name: string;
public constructor(name: string) {
this.name = name
}
getName(): string {
return this.name
}
}
const person = new Person('clz')
console.log(person.getName()) // clz
一般来说,一个类只能继承自另一个类。(C++可以多继承)
但是,有时候不同类之间有一些共有特性,可以将它们封装成接口。
就拿前面的Person
类举例子,所有人都需要吃、睡,即可以封装一个Normal
接口,包含必须的行为。然后通过implements
关键字去实现接口。接口只是声明,需要类通过implements
关键字实现
interface Normal {
eat(): void
sleep(): void
}
class Person implements Normal {
public name: string;
public constructor(name: string) {
this.name = name
}
eat() {
console.log('吃')
}
sleep() {
console.log('睡')
}
}
const person = new Person('clz')
person.eat() // 吃
还可以把Normal
接口分解成Eat
接口和Sleep
接口,然后同时实现两个接口。
interface Normal {
eat(): void
sleep(): void
}
class Person implements Normal {
public name: string;
public constructor(name: string) {
this.name = name
}
eat() {
console.log('吃')
}
sleep() {
console.log('睡')
}
}
const person = new Person('clz')
person.eat() // 吃
上面的Person类中省略了代码,代码和Normal
接口的案例一样。
interface Eat {
eat(): void
}
interface Drink {
drink(): void
}
interface Sleep {
sleep(): void
}
interface Normal extends Eat, Drink, Sleep { }