文章目录
1、定义类
定义类的示例:
class Person {
name: string;
constructor(name: string) { // 构造函数,实例化类的时候触发的方法
this.name = name;
}
getName(): string {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
let per = new Person('xiaoming');
2、类的继承
- 继承是一种oop(面向对象编程)的概念,它允许一个类继承另一个类的属性和方法
- 关键字:
extends
2.1 基本的继承:
class Animal {
move(distance: number) {
console.log('跑了' + distance + '米');
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark(); // Woof! Woof!
dog.move(10); // 跑了10米
这个例子展示了最基本的继承:类从基类中继承了属性和方法。
这里, Dog
是一个 派生类,它派生自 Animal
基类,通过 extends
关键字。
派生类通常被称作 子类,基类通常被称作 超类
2.2 包含构造函数的继承
- 派生类包含了一个构造函数,它 必须调用
super()
,它会执行基类的构造函数 - 在构造函数里访问
this
的属性之前,一定要调用super()
// 父类 class Animal { name: string; constructor(name: string) { this.name = name; } move(distance: number) { console.log(this.name + '跑了' + distance + '米'); } } // 使用 extends 关键字创建了 Animal的子类:Dog。 class Dog extends Animal { constructor(name: string) { super(name); // 必须调用 super() } // 子类里可以重写父类的方法 move(distance: number = 5) { console.log("Woofing..."); super.move(distance); } } // 使用 extends关键字创建了 Animal的子类:Snake。 class Snake extends Animal { constructor(name: string) { super(name); // 必须调用 super() } // 子类里可以重写父类的方法 move(distanceInMeters = 45) { console.log("Slithering..."); super.move(distanceInMeters); } } const dog = new Dog('二哈'); dog.move(10); const snake = new Snake('蛇'); snake.move();
3、修饰符
3.1 public
在TypeScript里,类的成员都默认为 public
class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
3.2 private
当成员被标记成 private
时,它就不能在声明它的类的外部访问,派生类也无法访问
class Animal {
private name: string;
constructor(theName: string) { this.name = theName }
run() {
console.log(this.name + '在叫'); // 允许
}
}
let dog = new Animal("dog");
dog.name; // 错误: 'name' 是私有的
dog.run() // 打印‘dog在叫’
子类中也不能访问该属性
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Dog extends Animal {
constructor(theName: string) {
super(theName);
}
run() {
console.log(this.name + '在叫'); // 错误
}
}
3.3 protected
protected
修饰符与 private
修饰符的行为很相似,不同的是protected
成员在派生类中仍然可以访问。
注意:我们不能在 Animal
类外使用 name
,但是我们仍然可以通过 Dog
类的实例方法访问
class Animal {
protected name: string;
constructor(theName: string) { this.name = theName; }
}
class Dog extends Animal {
constructor(theName: string) {
super(theName);
}
run() {
console.log(this.name + '在叫'); // 派生类中可以访问
}
}
let dog = new Dog('dog');
dog.run();
console.log(dog.name); // 错误(name不能在类外访问,只能通过实例方法去访问)
3.4 readonly
- 使用
readonly
关键字将属性设置为只读的 - 只读属性必须在声明时或构造函数里被初始化
class Person {
readonly name: string;
constructor(theName: string) {
this.name = theName;
}
}
let xiaoming = new Person('xiaoming');
xiaoming.name = 'xiaohong' // 错误! name 是只读的.
3、存取器
TypeScript 支持通过 getters/setters 来截取对对象成员的访问
注意:
- 存取器要求你将编译器设置为输出ECMAScript 5或更高
- 只带有
get
不带有set
的存取器自动被推断为readonly
// 我们先检查用户密码是否正确,然后再允许其修改员工信息
let passcode = "secret passcode";
class Employee {
private _fullName: string;
constructor(theName: string) {
this._fullName = theName;
}
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee('employee');
employee.fullName = "Bob Smith";
console.log(employee.fullName);
4、静态属性
- 关键字:
static
- 静态属性存在于类本身上面,而不是类的实例上
- 只能通过类名来访问静态属性
class Person {
static age = 24;
sayAge() {
return Person.age; // 通过类名访问
}
}
let p = new Person();
console.log(p.sayAge()); // 24
console.log(Person.age); // 24 通过类名访问
5、抽象类
- 所谓抽象类,是指只能被继承,但不能被实例化的类
- 抽象类两个特点:
- 抽象类不允许被实例化
- 抽象类中的抽象方法必须被子类实现
- 不同于接口,抽象类可以包含成员的实现细节
abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法
abstract class Animal { // 定义抽象类
abstract makeSound(): void; // 定义抽象方法
move(): void { // 抽象类可以包含成员的实现细节
console.log('roaming the earch...');
}
}
抽象类中的抽象方法不包含具体实现,并且必须在派生类中实现
// 定义抽象类
abstract class Department {
constructor(public name: string) {
}
abstract printMeeting(): void; // 必须在派生类中实现
}
// 派生类
class Account extends Department {
constructor() {
super('Account') // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log('Account printMeeting...');
}
}
let department: Department; // 允许创建一个对抽象类型的引用
department = new Department() // 错误: 不能创建一个抽象类的实例
department = new Account(); // 允许对一个抽象子类进行实例化和赋值
department.printMeeting();
6、高级技巧
6.1 构造函数
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter: Greeter;
greeter = new Greeter("world");
console.log(greeter.greet());
编译成 JavaScript
let Greeter = (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
})();
let greeter;
greeter = new Greeter("world");
console.log(greeter.greet());
6.2 把类当做接口使用
因为类可以创建出类型,所以你能够在允许使用接口的地方使用类
class Point {
x: number | undefined;
y: number | undefined;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = { x: 1, y: 2, z: 3 };
console.log(point3d);