TypeScript 类(Class)
自 ES6 起,终于迎来了 class
,对于开发者来说,终于可以使用基于类的面向对象式编程。TypeScript 在原 ES6 中类的基础上,还添加了一些新的功能,比如几种访问修饰符,这是在其他面向对象语言中早就实现了的。
JavaScript 的类作为语法糖,我们不但需要知道怎么去使用,还应该了解其本质,涉及到原型的部分希望大家能深入理解。
1. 解释
2. 类的本质
如果通过 class
关键字进行改写:
class Calculate {
// 类的属性
public x: number
public y: number
// 构造函数
constructor(x: number, y: number) {
this.x = x
this.y = y
}
// 类的方法
add () {
return this.x + this.y
}
}
const calculate = new Calculate(, )
console.log(calculate.add()) // 3
console.log(typeof Calculate) // 'function'
console.log(Calculate === Calculate.prototype.constructor) // true
代码解释:
3. 类的继承
基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类,这样可以抽出公共部分让子类复用。
使用 extends
关键字来实现继承:
// 继承 JavaScript 内置的 Date 对象
class LinDate extends Date {
getFormattedDate() {
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return this.getDate() + "-" + months[this.getMonth()] + "-" + this.getFullYear();
}
}
const date = new LinDate()
console.log(date.getFullYear()); // 2020
console.log(date.getFormattedDate()) // 7-Jan-2020
class Animal {
public name:string
constructor(name: string) {
this.name = name
}
move(distance: number = ) {
console.log(`${this.name} moved ${distance}m.`)
}
}
class Dog extends Animal {
constructor(name: string) {
// 调用父类的构造函数
super(name)
}
move(distance = ) {
console.log('bark...')
// 执行父类的方法
super.move(distance)
}
}
const dog: Animal = new Dog('Coco')
dog.move() // Coco moved 10m.
代码解释:
4. 访问修饰符
TypeScript 可以使用四种访问修饰符 public、protected、private 和 readonly。
4.1 public
class Calculate {
// 类的属性
public x: number
public y: number
// 构造函数
public constructor(x: number, y: number) {
this.x = x
this.y = y
}
public add () {
return this.x + this.y
}
}
4.2 protected
当成员被定义为 protected
后,只能被类的内部以及类的子类访问。
class Base {
protected baseUrl: string = 'http://api.com/'
constructor() {}
protected request(method: string) {
const url = `${this.baseUrl}${method}`
// Todo 封装基础的 http 请求
}
}
class Address extends Base {
get() {
return this.request('address')
}
}
代码解释:
4.3 private
当类的成员被定义为 private
后,只能被类的内部访问。
class Mom {
private labour() {
return 'baby is coming'
}
}
class Son extends Mom {
test () {
this.labour() // Error, Property 'labour' is private and only accessible within class 'Mom'
}
}
代码解释:
4.4 readonly
class Token {
readonly secret: string = 'xjx*xh3GzW#3'
readonly expired: number
constructor (expired: number) {
this.expired = expired
}
}
const token = new Token( * * )
token.expired = * * // Error, expired 是只读的
代码解释:
5. 静态方法
通过 static
关键字来创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。
class User {
static get@R_208_4045@ion () {
return 'This guy is too lazy to write anything.'
}
}
User.get@R_208_4045@ion() // OK
const user = new User()
user.get@R_208_4045@ion() // Error 实例中无此方法
class StaticmethodCall {
static staticmethod() {
return 'Static method has been called'
}
static anotherStaticmethod() {
return this.staticmethod() + ' from another static method'
}
}
class StaticmethodCall {
constructor() {
// 类本身调用
console.log(StaticmethodCall.staticmethod())
// 构造函数的属性调用
console.log(this.constructor.staticmethod())
}
static staticmethod() {
return 'static method has been called.'
}
}
6. 抽象类
抽象类作为其它派生类的基类使用,它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节。
abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法。
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}
const animal = new Animal() // Error, 无法创建抽象类实例
通常我们需要创建子类继承抽象类,将抽象类中的抽象方法一一实现,这样在大型项目中可以很好的约束子类的实现。
class Dog extends Animal {
makeSound() {
console.log('bark bark bark...')
}
}
const dog = new Dog()
dog.makeSound() // bark bark bark...
dog.move() // roaming the earch...
7. 把类当做接口使用
类也可以作为接口来使用,这在项目中是很常见的。
class Pizza {
constructor(public name: string, public toppings: string[]) {}
}
class PizzaMaker {
// 把 Pizza 类当做接口
static create(event: Pizza) {
return new Pizza(event.name, event.toppings)
}
}
const pizza = PizzaMaker.create({
name: 'Cheese and nut pizza',
toppings: ['pasta', 'eggs', 'milk', 'cheese']
})
第 7 行,把 Pizza 类当做接口。
这就是 TypeScript 的强大功能,而且非常灵活,拥有全面的面向对象设计和通用的类型检查。
8. 小结
本节介绍了类的本质及其使用方法,需要注意: