类
对于传统的 JavaScript 程序我们会使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员使用这些语法就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从 ECMAScript 2015,也就是
ES6
开始, JavaScript 程序员将能够使用基于类的面向对象
的方式。
使用 TypeScript,我们允许开发者现在就使用这些特性,并且编译后的 JavaScript 可以在所有主流浏览器和平台上运行,而不需要等到下个 JavaScript 版本。
类的基本定义与使用
// 类的基本定义与使用
class Greeter {
// 声明属性
message: string
// 构造方法
constructor(message: string) {
this.message = message
}
// 一般方法
greet(): string {
return 'Hello ' + this.message
}
}
// 创建类的实例
const greeter = new Greeter('world')
// 调用实例的方法
console.log(greeter.greet()) // Hello world
继承
在 TypeScript 里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
class Animal1 {
run(distance: number) {
console.log(`Animal run ${distance}m`)
}
}
class Dog extends Animal1 {
cry() {
console.log('wang! wang!')
}
}
const dog = new Dog()
dog.cry() // wang! wang!
dog.run(100) // 可以调用从父中继承得到的方法 // Animal run 100m
多态
- 父类型引用指向子类型的实例
- 不同类型的对象针对相同方法,产生不同行为
class Animal {
name: string
constructor(name: string) {
this.name = name
}
run(distance: number = 0) {
console.log(`${this.name} run ${distance}m`)
}
}
class Snake extends Animal {
constructor(name: string) {
// 调用父类型构造方法
super(name) // 派生类包含了一个构造函数,它必须调用 super()
}
// 重写父类型的方法
run(distance: number = 5) {
console.log('sliding...')
super.run(distance)
}
}
class Horse extends Animal {
constructor(name: string) {
// 调用父类型构造方法
super(name)
}
// 重写父类型的方法
run(distance: number = 50) {
console.log('dashing...')
// 调用父类型的一般方法
super.run(distance)
}
xxx() {
console.log('xxx()')
}
}
const snake = new Snake('sn')
snake.run()
const horse = new Horse('ho')
horse.run()
// 父类型引用指向子类型的实例 ==> 多态
const tom: Animal = new Horse('tom')
tom.run() // tom run 50m // Horse 默认为50
const jack: Animal = new Snake('jack')
jack.run() // jack run 5m // Snake 默认为5
/* 如果子类型没有扩展的方法, 可以让子类型引用指向父类型的实例 */
const tom1: Snake = new Animal('tom1')
tom1.run() // tom1 run 0m // Animal 默认为0
/* 如果子类型有扩展的方法, 不能让子类型引用指向父类型的实例 */
// const tom2: Horse = new Animal('tom2') // error
// tom2.run()
访问修饰符
用来描述类内部的属性/方法的可访问性
public: 默认值, 公开的外部也可以访问
private: 只能类内部可以访问
protected: 类内部和子类可以访问
class Person {
public name: string
public constructor(name: string) {
this.name = name
}
public run(distance: number = 0) {
console.log(`${this.name} run ${distance}m`)
}
}
class Boys extends Person {
private age: number = 18
protected sex: string = '男'
protected readonly height: number = 170 // 必须在声明时或构造函数里被初始化。
run(distance: number = 5) {
console.log('Boys jumping...')
super.run(distance)
}
}
class Girls extends Boys {
run(distance: number = 6) {
console.log('Girls jumping...')
// this.height = 160 // readonly 属性不可改
this.sex = '女'
console.log(this.sex) // 子类能看到父类中受保护的成员
// console.log(this.age) // 子类看不到父类中私有的成员
super.run(distance)
}
}
console.log(new Boys('abc').name) // 公开的可见
// console.log(new Boys('abc').sex) // 受保护的不可见
// console.log(new Boys('abc').age) // 私有的不可见
console.log(new Girls('cba').name)
new Girls('cba').run()
只读属性和参数属性
// 只读属性
class Person1 {
readonly name: string = 'abc'
constructor(name: string) {
this.name = name // 构造函数可以修改name属性
}
}
// 参数属性:把声明和赋值合并至一处。
class Person2 {
constructor(readonly name: string = 'hah') {
}
}
let john = new Person1('John')
console.log(john.name)
// john.name = 'peter' // error
const p = new Person2('jack')
console.log(p.name)
const p2 = new Person2()
console.log(p2.name) // hah
存取器
getters/setters 来截取对对象成员的访问
class Person3 {
firstName: string = 'A'
lastName: string = 'B'
get fullName() {
console.log('get...');
return this.firstName + '-' + this.lastName
}
set fullName(value) {
console.log('set...');
const names = value.split('-')
this.firstName = names[0]
this.lastName = names[1]
}
}
const p3 = new Person3()
console.log(p3.fullName) // A-B
p3.firstName = 'C'
p3.lastName = 'D'
console.log(p3.fullName) // C-D
p3.fullName = 'E-F'
console.log(p3.firstName, p3.lastName) // E F
静态属性
静态属性, 是类对象的属性(使用
static
修饰)
非静态属性, 是类的实例对象的属性
class Person4 {
name1: string = 'A'
static name2: string = 'B'
}
console.log(Person4.name2) // B
console.log(new Person4().name1) // A
抽象类
- 做为其它派生类的基类使用。 它们不能被实例化。不同于接口,抽象类可以包含成员的实现细节
abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法- 不能创建实例对象, 只有实现类才能创建实例,可以包含未实现的抽象方法
abstract class Animal2 {
abstract cry2():any// 抽象方法不能有具体的实现
run() {
console.log('run()')
}
}
class Dog2 extends Animal2 {
cry2() { // 抽象类的子类必须实现抽象类的抽象方法
console.log(' Dog cry()')
}
}
// const dog2:Animal2 = new Animal2() // error
const dog2 = new Dog2()
dog2.cry2()
dog2.run()