#

typescript 里的类和 javascript 里的类基本一样。 typerscript 扩展了类,它可以通过先声明的方式限制实例属性的类型,并且还引入了类似 C++Java 的继承权限设定,拥有 publicprotectprivate 三种修饰符。若不声明权限则默认为 public

修饰符外部访问派生类访问自身访问
public
protected×
private××

# public

public 修饰的属性可以在外部访问,也可以在派生类和自身实例中访问

class Person {
    name: string
    age: number
    constructor(name:string, age:number) {
        this.name = name
        this.age = age
    }
    say(): void {
        console.log(`My name is ${this.name},I'm ${this.age} years old`)
    }
}
class Student extends Person {
    course: string
    constructor(name:string, age:number, course:string) {
        super(name, age)
        this.course = course
    }
    say() {
        super.say()
        console.log(`My course is ${this.course}`)
    }
}
let man1: Person = new Person('sphinx', 16)
console.log(man1.name) // sphinx
man1.say() // My name is sphinx,I'm 16 years old
let man2: Student = new Student('asuhe', 16, 'math')
man2.say() // My name is asuhe,I'm 16 years old 
           // My course is math

# protected

protected 修饰的属性不可以在外部访问,但可以在派生类和自身实例中访问

class Person {
    protected name: string
    protected age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    say(): void {
        console.log(`My name is ${this.name},I'm ${this.age} years old`)
    }
}
class Student extends Person {
    course: string
    constructor(name: string, age: number, course: string) {
        super(name, age)
        this.course = course
    }
    say() {
        super.say()
        console.log(`My course is ${this.course}`)
    }
}
let man1: Person = new Person('sphinx', 16)
console.log(man1.name) // error
man1.say() // My name is sphinx,I'm 16 years old
let man2: Student = new Student('asuhe', 16, 'math')
man2.say() // My name is asuhe,I'm 16 years old 
           // My course is math

# private

protected 修饰的属性仅能自身实例中访问

class Person {
    private name: string
    private age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    say(): void {
        console.log(`My name is ${this.name},I'm ${this.age} years old`)
    }
}
let man1: Person = new Person('sphinx', 16)
console.log(man1.name) // error
console.log(man1.age) // error
man1.say() // My name is sphinx,I'm 16 years old

# readonly vs 权限修饰符

当我们希望一个属性仅可自身访问且仅可读取时,可以和 readonly 修饰符一起使用

class Goods {
	public readonly id:number
    constructor(id:number){
        this.id = id
    }
}

# 存取器

TypeScript 支持通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

下面来看如何把一个简单的类改写成使用 getset 。 首先,我们从一个没有使用存取器的例子开始。

class Person {
  firstName: string = 'A'
  lastName: string = 'B'
  get fullName () {
    return this.firstName + '-' + this.lastName
  }
  set fullName (value) {
    const names = value.split('-')
    this.firstName = names[0]
    this.lastName = names[1]
  }
}
const p = new Person()
console.log(p.fullName)
p.firstName = 'C'
p.lastName =  'D'
console.log(p.fullName)
p.fullName = 'E-F'
console.log(p.firstName, p.lastName)

# 抽象类

抽象类做为其它派生类的基类使用。 ** 它们不能被实例化。** 不同于接口,抽象类可以包含成员的实现细节。 abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法。

/* 
抽象类
  不能创建实例对象,只有实现类才能创建实例
  可以包含未实现的抽象方法
*/
abstract class Animal {
  abstract cry ()
  run () {
    console.log('run()')
  }
}
class Dog extends Animal {
  cry () {
    console.log('Dog cry()')
  }
}
const dog = new Dog()
dog.cry()  // Dog cry()
dog.run() // run()

# 抽象类 vs 接口

接口可以理解为里面所有属性都是 abstract ,而且使用了接口的类必须按接口的规格实现。接口的函数只能是定义,不能有函数体不能实现。

抽象类里的函数方法可以为 abstract 也可以不为 abstract ,而且抽象类的函数方法可以有函数体能够去实现。若抽象类的函数方法被实现类重写了,那么在实现类调用该方法时会调用实现类重写的那个方法。