一、概述
传统方法中,JavaScript 通过构造函数实现类的概念,通过原型链实现继承。在 ES6 中,我们迎来了 Class
。TypeScript 除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法。
二、示例
1. 属性修饰符
修飾符 | 描述 |
---|---|
public |
修饰公共属性/方法,可以在任何位置访问,所有属性和方法默认为 puiblic 。 |
private |
修饰私有属性/方法,不能在声明它的类的外部访问。 |
protected |
修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的。 |
readonly |
只读属性,必须在声明时或构造函数里被初始化。 |
static |
静态属性(类属性/类方法)→ 通过类名调用 |
我们来看一组示例:
// -- 定义一个Person 类
class Person {
/** 定义静态属性并直接赋值(TS会自动推断country类型为string) */
static country = "中国";
/** 定义一个公共属性(注意:public关键字可省略) */
public name: string;
/** 定义一个私有属性,构造实例时可以赋值,但是不能通过实例访问 */
private job: string;
/** 定义一个受保护的属性,只允许在Perosn及其子类中访问 */
protected birth: string;
/** 定义一个只读属性,只允许在构造时赋值 */
readonly gender: number;
/** 构造函数 */
constructor(name: string, job: string, birth: string, gender: number) {
this.name = name;
this.job = job;
this.birth = birth;
this.gender = gender;
}
}
const person = new Person("Li-HONGYAO", "前端工程师", "1993/07/16", 1);
console.log(Person.country); // 中国
console.log(person.name); // Li-HONGYAO
console.log(person.job); // Property 'job' is private and only accessible within class 'Person'.
console.log(person.birth); // Property 'birth' is protected and only accessible within class 'Person' and its subclasses.
person.gender = 0; // annot assign to 'gender' because it is a read-only property.
在 TypeScript 中,构造器允许简写:
class Person {
constructor(public name: string, private job: string, protected birth: string, readonly gender: number) {}
}
const person = new Person("Li-HONGYAO", "前端工程师", "1993/07/16", 1);
console.log(person.name); // Li-HONGYAO
console.log(person.job); // Property 'job' is private and only accessible within class 'Person'.
console.log(person.birth); // Property 'birth' is protected and only accessible within class 'Person' and its subclasses.
person.gender = 0; // annot assign to 'gender' because it is a read-only property.
2. 抽象类
abstract
用于定义抽象类和其中的抽象方法。什么是抽象类?
- 首先,抽象类是不允许被实例化的
- 其次,抽象类中的抽象方法必须被子类实现
// -- 定义一个抽象类
abstract class Person {
constructor(name: string) {}
/** 抽象属性,不用赋值,要求在子类中必须定义此属性并为其赋值 */
abstract job: string;
/** 抽象方法,不包含具体实现,要求在之类中必须实现此方法 */
abstract sayHello(name: string): void;
/** 非抽象方法,无需要求子类实现,但是子类可以重写此方法 */
running() {
console.log("I'm running!");
}
}
class Teacher extends Person {
// Non-abstract class 'Teacher' does not implement inherited abstract member 'job' from class 'Person'.
// Non-abstract class 'Teacher' does not implement inherited abstract member 'sayHello' from class 'Person'.
}
class Student extends Person {
/** 实现抽象属性 */
job: string;
name: string;
constructor(name: string, job: string) {
super(name);
this.job = job;
this.name = name;
}
/** 实现抽象方法 */
sayHello(name: string) {
console.log(`Hello, ${name}!`);
}
/** 重写抽象类方法 */
running() {
console.log("I'm studing!")
}
}
const stu = new Student("Li-HONGYAO", '前端工程师');
console.log(stu.job); // 前端工程师
console.log(stu.name); // Li-HONGYAO
stu.sayHello("Li-HONGYAO"); // Hello, Li-HONGYAO!
stu.running(); // "I'm studing!"
三、类与接口
接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述,通常,通过接口可以约束一个类的形状,只需要让这个类实现这个接口即可。
1. 类实现接口
实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements
关键字来实现。这个特性大大提高了面向对象的灵活性。
举例来说,人是一个类,学生是人的子类。学生具备姓名属性和说话的能力,我们可以给学生添加一个姓名属性和说话的方法。这时候如果有另一个类,老师,也有姓名属性和说话的能力,这个时候,就可以把姓名属性和说话的方法提取出来,作为一个接口,老师和学生都去实现它:
interface Person {
name: string
speack: () => void;
}
class Teacher implements Person {
name: string;
constructor(name: string) {
this.name = name;
}
speack() {
console.log("我是一名老师!");
}
}
class Student implements Person {
name: string;
constructor(name: string) {
this.name = name;
}
speack() {
console.log("我是一名学生!");
}
}
一个类可实现多个接口,中间以逗号 ,
隔开:
interface Person {
name: string,
speack: () => void;
}
interface Teach {
course: string;
}
class Teacher implements Person, Teach {
name: string;
course: string;
constructor(name: string, course: string) {
this.name = name;
this.course = course;
}
speack() {
console.log(`我是一名${this.course}老师!`);
}
}
上述示例中,Teacher 类实现了Person 和 Teach 接口。
2. 接口继承类
class Point {
x: number = 0;
y: number = 0;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = { x: 1, y: 2, z: 3 };
四、单例模式
接下来我们看看如何在 TypeScript 中定义一个单例:
class Singleton {
name: string = '';
private static instance: Singleton;
private constructor() {}
static defaultSingleton() {
if(!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}
const single1 = Singleton.defaultSingleton();
const single2 = Singleton.defaultSingleton();
console.log(single1 === single2); // true
single1.name = 'Muzili';
console.log(single2.name); // Muzili