- Published on
TypeScript - Classes
- Authors
- Name
- Deng Hua
目录
- Annotating Classes In TypeScript
- Readonly Class Properties
- The Public Modifier
- The Private Modifier
- Parameter Properties Shorthand
- Getter and Setter
- The Protected Modifier
- Classes and Interface
- Abstract Classes
Annotating Classes In TypeScript
在typescript中,我们不能直接在构造函数中初始化一个属性而不“事先通知”TS
class Player {
constructor(first: string, last: string) {
this.first = first // ❌ 类型“Player”上不存在属性“first”
this.last = last // ❌ 类型“Player”上不存在属性“last”
}
}
属性注释
class Player {
first: string
last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
}
const elton = new Player('Elton', 'Steele')
Readonly Class Properties
在类中使用readonly
语法
class Player {
readonly first: string
readonly last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
}
const elton = new Player('Elton', 'Steele')
elton.first = 'elton' // ❌ 无法为“first”赋值,因为它是只读属性。
The Public Modifier
默认情况下,在javascript或typescript中,类中的每个属性,每个方法都被认为是公共的,它们都能被所属的实例访问。
当然也可以显式的使用public
关键字注释属性。注意这是typescript的语法。
class Player {
public first: string
public last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
}
const elton = new Player('Elton', 'Steele')
elton.first // ✅
这样明确了该属性是否是可写的,可访问的等等。
当然,也可以与readonly
搭配使用,即只可访问。
class Player {
public readonly first: string
public last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
}
const elton = new Player('Elton', 'Steele')
elton.first = 'john' // ❌ 无法为“first”赋值,因为它是只读属性
The Private Modifier
使用private
关键字,可以使属性只能在类内部访问与使用,无法在类外部访问它。
class Player {
private first: string
public last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
}
const elton = new Player('Elton', 'Steele')
elton.first // ❌ 属性“first”为私有属性,只能在类“Player”中访问
当然,我们知道在ES6中也有属性私有的标识符
class Player {
private first: string
#last: string
constructor(first: string, last: string) {
this.first = first
this.#last = last
}
}
const elton = new Player('Elton', 'Steele')
elton.first // ❌ 属性“first”为私有属性,只能在类“Player”中访问
elton.#last // ❌ 属性 "#last" 在类 "Player" 外部不可访问,因为它具有专用标识符
但两者不能一同使用。
class Player {
private first: string
#last: string
private #fullName: string // ❌ 可访问性修饰符不能与专用标识符一起使用
constructor(first: string, last: string) {
this.first = first
this.#last = last
}
}
更推荐在TS中只使用private
关键字。
补充类的私有方法:
class Player {
private first: string
last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
this.privateMethod() // ✅ because this call in inside the class
}
private privateMethod() {
console.log('secret method')
}
}
const elton = new Player('Elton', 'Steele')
elton.privateMethod // ❌ 属性“privateMethod”为私有属性,只能在类“Player”中访问
Parameter Properties Shorthand
有一种更快捷的方式声明一个类
class Player {
constructor(
public first: string,
public last: string
) {}
private privateMethod() {
console.log('secret method')
}
}
const elton = new Player('Elton', 'Steele')
Getter and Setter
class Player {
first: string
last: string
private _score: number
constructor(first: string, last: string) {
this.first = first
this.last = last
}
get fullName(): string {
return `${this.first} ${this.last}`
}
get score(): number {
return this._score
}
set score(newScore: number) {
this._score = newScore
}
}
const elton = new Player('Elton', 'Steele')
elton.fullName
elton.score
elton.score = 99
The Protected Modifier
假设我们有一个子类需要继承之前的Player
,但是我们想在子类中访问Player
的私有属性。
class Player {
first: string
last: string
private _score: number
constructor(first: string, last: string) {
this.first = first
this.last = last
}
get fullName(): string {
return `${this.first} ${this.last}`
}
get score(): number {
return this._score
}
set score(newScore: number) {
this._score = newScore
}
}
class SuperPlayer extends Player {
public isAdmin: boolean = true
maxScore() {
this._score = 999999 // ❌ 属性“_score”为私有属性,只能在类“Player”中访问
}
}
const elton = new Player('Elton', 'Steele')
elton.fullName
elton.score
elton.score = 99
使用private
修饰的属性或方法,在子类中也是不允许访问,有什么方法能够保证属性即是私有,同时也能在子类中能够被访问?
可以使用protected
关键字。
class Player {
first: string
last: string
protected _score: number
constructor(first: string, last: string) {
this.first = first
this.last = last
}
get fullName(): string {
return `${this.first} ${this.last}`
}
get score(): number {
return this._score
}
set score(newScore: number) {
this._score = newScore
}
}
class SuperPlayer extends Player {
public isAdmin: boolean = true
maxScore() {
this._score = 999999
}
}
const elton = new SuperPlayer('Elton', 'Steele')
elton.maxScore()
Classes and Interface
实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。 ———— 类实现接口
interface Colorful {
color: string
}
class waterMelon implements Colorful {
color = 'green'
}
class strawBerry implements Colorful {
color = 'red'
}
也可以implements
多个接口
interface Colorful {
color: string
}
interface Printable {
print(): void
}
class waterMelon implements Colorful, Printable {
color = 'green'
print() {}
}
Abstract Classes
abstract 用于定义抽象类和其中的抽象方法。
抽象类,不能被实例化的的类
abstract class Cat {}
new Cat() // ❌ 无法创建抽象类的实例
不能被实例的类有什么意义呢?
实际上,抽象类更像是定义了一种模式,定义了必须由子类实现的方法。
abstract class Employee {
first: string
last: string
constructor(first, last) {
this.first = first
this.last = last
}
abstract getPay(): number // 表示getPay方法需要存在于任何继承了Employee的类中
}
是不是有点像interface
的作用,但不同的是,抽象类还可以在内部定义真实可用的方法。
abstract class Employee {
first: string
last: string
constructor(first, last) {
this.first = first
this.last = last
}
abstract getPay(): number // 表示getPay方法需要存在于任何继承了Employee的类中
print() {
console.log('hello')
}
}
实现抽象类
abstract class Employee {
first: string
last: string
constructor(first, last) {
this.first = first
this.last = last
}
abstract getPay(): number // 表示getPay方法需要存在于任何继承了Employee的类中
print() {
console.log('hello')
}
}
class FullTime extends Employee {
getPay(): number {
return 1
}
}
class PartTime extends Employee {
getPay(): number {
return 0.5
}
}
以上两个子类都必须实现getPay
方法
我们可以继续拓展子类
abstract class Employee {
first: string
last: string
constructor(first, last) {
this.first = first
this.last = last
}
abstract getPay(): number // 表示getPay方法需要存在于任何继承了Employee的类中
}
// 全职
class FullTime extends Employee {
constructor(
first: string,
last: string,
private salary: number
) {
super(first, last) // 公共继承的属性
}
getPay(): number {
return this.salary
}
}
// 实习
class PartTime extends Employee {
constructor(
first: string,
last: string,
private hourlyRate: number,
private hoursWorked: number
) {·
super(first, last) // 公共继承的属性
}
getPay(): number {
return this.hourlyRate * this.hoursWorked
}
}
const betty = new FullTime('Betty', 'White', 95000)
const bill = new PartTime('Bill', 'Willington', 24, 72)
betty.getPay()
bill.getPay()