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 成员,把声明和赋值合并至一处了。
参数属性简单来说就是在 constructor 构造函数的参数前面加上访问限定符,也就是前面说的 public、private、protected 和 readonly 中的任意一个。
静态属性
在 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){}
}