类
typescript 是面向对象的 javascript,类描述了所创建的对象共同的属性和方法,typescript 支持面向对象的所有特性,比如 类、接口等。定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块。
字段
字段是类里面声明的变量,字段表示对象的有关数据。
class Rect {
x: number;
y: number;
}
构造函数 constructor
类实例化的时候调用,可以为类的对象分配内存。
class Rect {
constructor(public x: number, public y: number) {}
getPos() {
return { x: this.x, y: this.y };
}
}
let position = new Rect(100, 100);
position.getPos();
方法
方法为对象要执行的操作
class Rect {
x: number;
y: number;
getPos() {
return { x: this.x, y: this.y };
}
}
类的继承
typescript 支持继承类,即我们可以在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。typescript 一次只能继承一个类,不支持继承多个类,但 typescript 支持多重继承(A 继承 B,B 继承 C)。
B 继承了 A,所以 B 的实例有 A 中的 print 方法。
class A {
print() {
console.log("Hello!!!");
}
}
class B extends A {}
const b = new B();
b.print();
需要注意的是子类只能继承一个父类,typescript 不支持继承多个类,但支持多重继承。
class A {
print() {
console.log("Hello!!!");
}
}
class B extends A {}
class C extends B {}
const c = new C();
c.print();
继承类的方法重写
子类可以覆盖基类的同名方法,这个过程称之为方法的重写。下面子类 C 重写了基类 A 的同名方法 print。
class A {
print(): void {
console.log("Hello!!!");
}
}
class B extends A {}
class C extends B {
print(name?: string): void {
if (name === void 0) {
super.print();
} else {
console.log(`Print name is ${name}`);
}
}
}
const c = new C();
c.print("rinvay");
类和接口
类可以 使用关键字 implements 实现接口,接口字段作为类的属性使用。
implements 关键字
interface 或 type 都可以定义一个对象类型。类使用 implements 关键字,表示该类的实例对象满足这个对象类型。
interface Rect {
x: number;
y: number;
}
type Point = {
x: number;
y: number;
};
class A implements Rect {
x = 0;
y = 0;
}
class B implements Rect {
x = 100;
y = 100;
}
类可以实现多个接口(其实是接受多重限制),每个接口之间使用逗号分隔。
interface Rect {
x: number;
y: number;
}
type Point = {
z: number;
};
class A implements Rect, Point {
x = 0;
y = 0;
z = 0;
}
同时实现多个接口并不是一个好的写法,容易使得代码变得难以维护,可以使用下面的方法替代。
interface Rect {
x: number;
y: number;
}
interface Point {
z: number;
}
interface Coordinate extends Rect, Point {}
class A implements Coordinate {
x = 0;
y = 0;
z = 0;
}
抽象类
TypeScript 允许在类的定义前面加上关键字 abstract,表示该类不能被实例化,只能当作其他类的模板,这种类就叫做“抽象类”。
abstract class A {}
const a = new A(); // error 无法创建抽象类的实例。
抽象类的内部可以有已经实现好的属性和方法,也可以有还未实现的属性和方法。后者在前面加上关键字abstract 之后就叫做“抽象成员”,表示该方法需要子类实现。如果子类没有实现抽象成员就会报错,抽象成员只能存在于抽象类中。
abstract class A {
abstract print(): void;
}
class B extends A {} // error 非抽象类‘B’不实现‘A’的所有抽象成员
// ok
abstract class A {
abstract print(): void;
}
class B extends A {
print(): void {
console.log("Hello!!!");
}
}
static 关键字
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticRect {
static x: number;
static y: number;
static display(): void {
console.log(StaticRect.x, StaticRect.y);
}
}
StaticRect.x = 100;
StaticRect.y = 100;
StaticRect.display();
const rect = new StaticRect();
rect.display(); // error 属性“display”在类型“StaticRect”上不存在。
上面示例中,x,y 是静态属性,display 是静态方法。它们都必须通过 StaticRect 获取,而不能通过实例对象调用,static 关键字前面可以使用 public 、 private 、 protected 修饰符。
可访问性修饰符
TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
public(默认)
公有成员,可以在任何地方被访问。
class Rect {
public x: number = 100;
public y: number = 100;
public display(): void {
console.log(this.x, this.y);
}
}
const rect = new Rect();
rect.x = 200;
rect.y = 200;
rect.display();
protected
受保护成员,可以被其自身以及其子类访问,实例无法使用该成员,但是子类内部可以使用。
class Rect {
protected x: number = 100;
public y: number = 100;
public display(): void {
console.log(this.x, this.y);
}
}
class A extends Rect {
print() {
console.log(this.x); // ok
}
}
const rect = new A();
rect.x; // error 属性“x”受保护,只能在类“Rect”及其子类中访问。
rect.y; // ok
子类 A 中 能访问受保护成员 x ,实例 rect 中不能通过 rect.x 访问受保护成员 x。
private
私有成员,只能被其定义所在的类访问,类的实例和子类都不能使用该成员。
class Rect {
private x: number = 100;
public y: number = 100;
public display(): void {
console.log(this.x, this.y);
}
}
class A extends Rect {
print() {
console.log(this.x); // error 属性“x”为私有属性,只能在类“Rect”中访问。
}
}
const rect = new A();
rect.x; // error 属性“x”为私有属性,只能在类“Rect”中访问。
rect["x"]; // ok
rect.y;
rect.print();
子类 A 中 不能访问私有变量 x ,实例 rect 中也不能通过 rect.x 访问私有变量 x。但是 可以 通过 rect["x"] 访问,所以严格地说,private 定义的私有变量,并不是真正意义的私有变量。在编译成 js 之后,private 关键字就掉了,这时外部访问该私有变量就不会报错。而 es6 引入了真正意义上的私有变量写法#prop。因此建议不使用 private,改用 es6 写法,获得真正意义上的私有变量。