typescript 中的类与 es6 中的类在使用上基本一样,举个小例子:
class Person{ name:string; constructor(name:string){ this.name = name } sayHi(){ console.log('hi') } } // 定义 Teacher 继承 Person class Teacher extends Person{ constructor(name:string){ super(name) } teach(){ console.log('teach') } } const teacher = new Teacher('Tom') console.log(teacher.name) // Tom teacher.sayHi() // hi teacher.teach() // teach
例子中实现了类的基本定义以及类的继承。如果了解 es6 的话,理解起来不难,需要注意的是 typescript 中强制你在派生类的构造函数中必须调用 super(),即在构造函数里访问 this
的属性之前,我们一定要调用 super(),它执行基类的构造函数。
基类是指父类,也被叫做“超类”,派生类则是子类。
修饰符
typescript 中为类提供了四个修饰符,分别是 public(公共的)、private(私有的)和 protected(受保护的),还有一个 readonly(只读)。
public
默认情况下 typescript 中定义的属性和方法都是公共的,即可以在类的外部访问到。有时 TSLint 可能会要求你必须用修饰符来表明这个属性或方法是什么类型的,手动添加即可,如下:
class Point{ public x:number; public y:number; constructor(x:number,y:number){ this.x = x this.y = y } public getPosition(){ return `${this.x}:${this.y}` } }
private
当成员被标记成 private
时,它就不能在声明它的类的外部访问。比如:
class Animal{ private name:string; constructor(name:string){ this.name = name } getName(){ console.log(this.name) } } const cat = new Animal('cat') console.log(cat.name) // Property 'name' is private and only accessible within class 'Animal'. cat.getName() // cat
protected
protected 与 private 类似,区别在于被 protected 标记的属性可以在子类中访问到,而 private 标记的属性不能在子类中访问到。
class Person{ protected name:string; constructor(name:string){ this.name = name } } class Student extends Person{ private age:number; constructor(name:string,age:number){ super(name) this.age = age } getName(){ console.log(this.name) } } const s = new Student('小明',18) s.getName() // 小明 console.log(s.name) // 属性 “name” 受保护,只能在类 “Person”及其子类中访问
上述例子中,name 属性可以在子类 Student 中获取,但是在类的外部就获取不到了。
protected 还可以标记构造函数,意味着这个被标记的类不能被实例化,只能继承:
class Person{ protected constructor(){ } } const p = new Person() // 类 “Person” 的构造函数是受保护的,仅可在类声明中访问 class Student extends Person{ constructor(){ super() } } const s = new Student()
readonly
使用 readonly
关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class UserInfo{ readonly name:string; constructor(name:string){ this.name = name } } const user = new UserInfo('Tom') user.name = 'Bob' // Cannot assign to 'name' because it is a read-only property
参数属性
参数属性可以用来简化一个过程。什么过程?就拿上面的例子来说,我们在 UserInfo 类里,定义一个只读属性 readonly 和一个参数为 name 的构造函数,然后要在构造函数中进行 this.name = name 的赋值,这种操作是经常遇到的,利用参数属性我们可以简化这个过程,变成如下这样:
class UserInfo{ constructor(readonly name:string){} } const user = new UserInfo('Tom') console.log(user.name) // Tom
现在仅在构造函数里使用 readonly name: string
参数来创建和初始化 name
成员,把声明和赋值合并至一处了。
静态属性
在 TS 中使用 static 关键字来指定属性或方法是静态的,实例不会添加这个静态属性,也不会继承静态方法。
class Car{ static color:string = 'red'; getColor(){ console.log(Car.color) } constructor(){ // } } const p = new Car() console.log(p.color) // Property 'color' is a static member of type 'Car' p.getColor() // red
可选属性
使用 ? 符号来标记可选属性:
class Info{ name:string; age?:number; constructor(name:string,age?:number,sex?:string){ this.name = name this.age = age } } const info1 = new Info('A') const info2 = new Info('B',18) const info3 = new Info('C',18,'man')
存取器
存取器即是存值函数和取值函数,也就是在设置属性值的时候调用的函数,和在访问属性值的时候调用的函数,使用关键词 get 和 set。
class Info{ private _name:string; get name(){ // 在获取值前,可以做一些判断操作 return this._name } set name(value){ // 在设置值前,可以做一些判断操作 this._name = value } constructor(){ // } } const info = new Info() info.name = 'Tom' console.log(info.name) // Tom
抽象类
抽象类用来被其他类继承,而不能被实例化,使用 abstract
关键字定义抽象类和在抽象类内部定义抽象方法。
abstract class People{ name:string constructor(name:string){this.name = name} abstract printName():void } class Man extends People{ constructor(name:string){ super(name) } // 抽象方法无法从父类继承,需要自己实现 printName(){ console.log(this.name) } } const m = new Man('Tom') m.printName() // Tom const p = new People() // 无法创建抽象类的实例
abstract 关键字也可以定义抽象属性和抽象存取器:
abstract class People{ abstract name:string abstract printName():void abstract get insideName():string abstract set insideName(value:string) constructor(name:string){} }