一、基本用法
可以使用class
关键字来声明一个类,类里面可以声明属性
和方法
,如:
class ClassName {
prop: type // 声明属性
// 声明构造器
constructor() {
}
// 声明方法
methodName() {
}
}
然后可以使用new
关键字来实例化一个类,如:let p = new ClassName()
二、继承
typescript里,同样可以使用常用的面向对象模式,如类的继承,继承使用extends
关键字,需要注意的是,一旦子类里显式
声明了constructor
方法,那么方法内部就必须使用super()
方法来调用父类构造器,示例如:
class A {
prop1: string
method1() {
// ...
}
}
class B extends A {
prop2: number
constructor() {
super()
}
method2() {
// ...
}
}
三、访问控制
1、public/private/protected
typescript支持与其他语言类似的访问控制修饰符:public
、private
、protected
,可以在属性
和方法
的前面加上访问控制符来控制访问权限,默认情况下,访问权限为public
,示例如:
class A {
prop1: string // 不加修饰符,默认为public,可被类自身、类外、子类访问
public prop2: string // 可被类自身、类外、子类访问
private prop3: string // 只能被类自身访问,类外、子类不能访问
protected prop4: string // 只能被类自身、子类访问,类外不能访问
}
注意:typescript使用的是结构性类型系统,所以当比较两种不同的类型时,如果所有的成员的类型都是兼容的,那么这两个类型就是兼容的,如:
class A {
prop1: string
}
class B {
prop1: string
prop2: string
}
let instance:A = new B() // 允许这么做,因为A的所有成员类型,B中都有
但是如果被比较的类里面含有private
和protected
类型成员的时候,情况就不同了,这时候需要另一个类里也含有这个private
/protected
成员,类型才能是兼容的,所以有:
class A {
private prop1: string
}
class B {
private prop2: string
}
let p1:A = new B() // 报错
class C extends A {
}
let p2:A = new C() // 允许这么做
2、readonly修饰符
可以使用readonly
将属性设为只读的,只读属性必须在声明时或者构造函数里初始化,如:
class A {
readonly prop1: string
}
let a = new A()
a.prop1 = 'HelloWorld' // 报错,因为只能在声明时或者构造函数里初始化
所以正确的方式为:
class A {
readonly prop1: string = 'HelloWorld'
}
// 或者
class A {
readonly prop1: string
constructor() {
this.prop1 = 'HelloWorld'
}
}
3、参数属性
参数属性允许同时创建
和初始化
成员,可以把声明和赋值合并至一处,如:
class A {
constructor(private name: string) {
}
}
这等价于:
class A {
private name: string
constructor(name: string) {
this.name = name
}
}
4、存取器
typescript支持getter
和setter
,但是有一点限制:编译器输出必须设为ES5或者更高,不支持降级到ES3。getter和setter的用法如:
class A {
get prop1() {
// ...
}
set prop1() {
// ...
}
}
let a:A = new A()
a.prop1 // 此时调用getter
a.prop1 = xxx // 此时调用setter
当一个存取器只带有get
却不带有set
时,它会被自动推断为readonly
5、静态属性
可以使用static
来定义类里的静态属性,静态属性属于类自身,而不属于实例,访问的时候要用类名访问,而不能用实例对象访问,如:
class ClassName {
static propName: string
}
ClassName.propName // 可以访问
let p = new ClassName()
p.propName // 不能访问
四、抽象类
抽象类
只能作为其他派生类的基类
使用,抽象类不能被实例化,它具有如下特点:
1)抽象类可以包含成员的实现细节,且抽象类必须用abstract
声明
2)抽象类里不含方法体的方法称为抽象方法,使用abstract
声明,抽象方法必须被子类实现(抽象方法必须使用abstract
关键字声明,且可以包含访问修饰符)
所以有:
abstract class AbstractClass {
greet() {
console.log('Hello, world')
}
abstract method()
}
let p = new AbstractClass() // 不允许
// 以下代码会报错,因为没有实现全部的抽象方法
class A extends AbstractClass {
}
3)private
修饰符不能与abstract
修饰符一起使用
4)使用abstract
修饰符,则子类中需要有同样或更高的访问权限,如:
// 情况一:报错
abstract class AbstractClass {
private abstract a
}
class Sub extends AbstractClass {
private a
}
// 情况二:可行
abstract class AbstractClass {
protected abstract a
}
class Sub extends AbstractClass {
public a
}
// 情况三:不可行
abstract class AbstractClass {
protected abstract a
}
class Sub extends AbstractClass {
private a
}