类的声明 & 实现
TS为成员属性和构造函数的参数添加了类型注解 run方法默认返回值是void
class Dog {
constructor(name: string) {
this.name = name
}
name: string
run() {}
}
注:
无论是在ES还是TS中,类的成员属性都是实例属性(而不是原型属性),类的成员方法都是原型方法
打印类的原型,查看是否包含内部属性
console.log(Dog.prototype)
类的原型不包含内部属性,原型上只有 run 方法和 constructor 构造方法
创建一个实例,并且输出
class Dog {
constructor(name: string) {
this.name = name
}
name: string
run() {}
}
console.log(Dog.prototype)
let dog = new Dog('wangcai')
console.log(dog)
可以看到,内部属性 name 只在实例上,而不在原型上
异同点:
- 在TS实例的属性必须有初始值,或在构造函数中被初始化
- 如删掉构造函数中对name的初始化,将提示错误
- 如下代码所示:
class Dog {
constructor(name: string) {
// this.name = name;
}
name: string
run() {}
}
console.log(Dog.prototype)
let dog = new Dog('wangcai')
console.log(dog)
处理:
// 初始值
{
class Dog {
constructor(name: string) {
// this.name = name;
}
name: string = 'Dog'
run() {}
}
console.log(Dog.prototype)
let dog = new Dog('wangcai')
console.log(dog)
}
// 可选属性
{
class Dog {
constructor(name: string) {
// this.name = name;
}
name?: string
run() {}
}
console.log(Dog.prototype)
let dog = new Dog('wangcai')
console.log(dog)
}
总结:只要内部属性有初始值,就不会报错
继承
类的继承使用了extends关键字 类的构造函数constructor中调用了super,代表父类实例 父类Dog的构造函数中有一个参数name,所以子类也必须要有具有此参数
// 继承
class Husky extends Dog {
constructor(name: string, color: string) {
super(name)
this.color = color
}
color: string
}
成员修饰符
类的成员修饰符部分是TS对ES所做的扩展
公有成员-public
类的所有属性默认均为public,表示对所有人可见
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
run() {}
}
私有成员-private
私有成员,只能在类的本省调用,而不能被类的实例调用,也不能被子类调用
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
// name: string = 'dog'
run() {}
// 私有成员,只能在类的本省调用,而不能被类的实例调用,也不能被子类调用
private pri() {}
}
let dog = new Dog('wangwang')
console.log(dog) // Dog {legs: 4, name: "wangwang"}
dog.pri()
私有成员也不能在子类中被调用
类的构造函数也可以被设置为私有成员,既不能被实例化也不能被继承了
// 类
class Dog {
private constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
}
let dog = new Dog('wangwang')
class Husky extends Dog {
constructor(
name: string,
public color: string
) {
super(name)
this.color = color
}
}
受保护成员-protected
受保护成员,只能在类或者子类访问与调用,而不能在类的实例访问
// 类
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
protected pro() {}
}
let dog = new Dog('wangwang')
dog.pro()
// 继承
class Husky extends Dog {
constructor(
name: string,
public color: string
) {
super(name)
this.color = color
this.pro()
}
// color: string;
}
构造函数也可以被声明为 protected,使这个类只能被继承,不能被实例化,相当于声明了一个基类
// 类
class Dog {
protected constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
protected pro() {}
}
let dog = new Dog('wangwang')
// 继承
class Husky extends Dog {
constructor(
name: string,
public color: string
) {
super(name)
this.color = color
this.pro()
}
// color: string;
}
只读属性-protected
只读属性,这个属性不能被更改,而且不能被更改 和实例属性一样,类的只读属性必须被初始化
// 类
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
protected pro() {}
readonly legs: number = 4
}
let dog = new Dog('wangwang')
console.log(dog) // Dog {legs: 4, name: "wangwang"}
静态成员-static
类的静态成员只能通过类名来调用,不能通过子类来调用 类的静态成员可以被继承
// 类
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
protected pro() {}
readonly legs: number = 4
static food: string = 'bones'
}
let dog = new Dog('wangwang')
console.log(dog.food)
console.log(Dog.food) // bones
// 继承
class Husky extends Dog {
constructor(
name: string,
public color: string
) {
super(name)
this.color = color
this.pro()
}
}
console.log(Husky.food) // bones
构造函数的参数添加修饰符
除了类的成员可以添加修饰符外,构造函数的参数也可以添加修饰符 作用:将参数自动变成实例的属性,这样就可以省略在类中的定义
// 类
class Dog {
constructor(name: string) {
this.name = name
}
public name: string
run() {}
private pri() {}
protected pro() {}
readonly legs: number = 4
static food: string = 'bones'
}
// 继承
class Husky extends Dog {
constructor(
name: string,
public color: string
) {
super(name)
this.color = color
this.pro()
}
color: string
}
抽象类的定义
抽象类只能被继承,不能被实例化 定义抽象类使用abstract关键字
abstract class Animal {}
let animal = new Animal()
抽象类的继承
继承抽象类,需要在子类中调用super方法
abstract class Animal {
eat() {
console.log('eat')
}
}
class Dog extends Animal {
constructor(name: string) {
super()
this.name = name
}
name: string
run() {}
}
let dog = new Dog('wangwang')
console.log(dog.name)
抽象类实现方法复用
在抽象类中可以定义方法(可以有具体实现,也可以是抽象方法),从而实现复用 抽象类可以抽离事物的共性,有利于代码的复用和扩展
abstract class Animal {
eat() {
console.log('eat')
}
abstract sleep(): void
}
class Dog extends Animal {
constructor(name: string) {
super()
this.name = name
}
name: string
sleep() {
console.log('Dog sleep')
}
}
let dog = new Dog('wangwang')
dog.eat()
dog.sleep()
class Cat extends Animal {
sleep() {
console.log('Cat sleep')
}
}
let cat = new Cat()
cat.eat()
cat.sleep()
抽象类实现多态
通过在父类中定义抽象方法,在不同子类中对该方法进行不同实现, 从而在运行时根据不同子类对象表现为不同状态
abstract class Animal {
eat() {
console.log('eat')
}
abstract sleep(): void
}
class Dog extends Animal {
constructor(name: string) {
super()
this.name = name
}
name: string
sleep() {
console.log('Dog sleep')
}
}
let dog = new Dog('wangwang')
dog.eat()
dog.sleep()
class Cat extends Animal {
sleep() {
console.log('Cat sleep')
}
}
let cat = new Cat()
cat.eat()
cat.sleep()
let animal: Animal[] = [dog, cat]
animal.forEach((i) => {
i.sleep()
})
this类型
类的成员方法可以直接返回一个this,方便实现链式调用,即Builder模式
class WorkFlow {
step1() {
return this
}
step2() {
return this
}
}
new WorkFlow().step1().step2()
使用this实现多态
this代表实例本身,继承时,子类实例即可表现多态(this既可以是父类,也可以是子类)
class WorkFlow {
step1() {
return this
}
step2() {
return this
}
}
new WorkFlow().step1().step2()
class Myflow extends WorkFlow {
next() {
return this
}
}
new Myflow().next().step1().next().step2()
接口对类的约束作用
接口能够对类的成员属性和类型进行约束(且只能约束类的公有成员) 注意: 类必须实现接口中声明的全部属性和方法 类可以新增独有的属性和方法
interface Human {
// new(name: string): void
name: string
eat(): void
}
// 类实现接口的时候,必须实现接口所有声明的属性
// 接口只能约束类的共有成员
// 接口不能约束构造函数
class Asion implements Human {
constructor(name: string) {
this.name = name
}
name: string
eat() {}
sleep() {}
}
接口继承
接口和类一样,可以相互继承,且一个接口可以继承多个接口 接口的继承特性可以将可重用部分进行抽离,也可以将多个接口合并成一个接口
interface Human {
// new(name: string): void
name: string
eat(): void
}
// 类实现接口的时候,必须实现接口所有声明的属性
// 接口只能约束类的共有成员
// 接口不能约束构造函数
class Asion implements Human {
constructor(name: string) {
this.name = name
}
name: string
eat() {}
sleep() {}
}
// 接口继承
interface Man extends Human {
run(): void
}
// 具有另外行为的接口
interface Child {
cry(): void
}
// 多个接口组合使用
interface Boy extends Man, Child {}
// 属性与方法
let boy: Boy = {
name: '',
run() {},
eat() {},
cry() {},
}
接口继承类
接口除了可以继承接口外,还可以继承类,相当于将类成员全部抽象出来,仅有类的结构而没有具体实现 注意: 接口抽离类成员时,不仅抽离了公共成员,也抽离了私有成员和受保护成员
class Auto {
state = 1
// private state2 = 0;
}
interface AutoInterface extends Auto {}
class C implements AutoInterface {
state = 1
}
class Auto {
state = 1
// private state2 = 0;
protected state3 = 3
}
interface AutoInterface extends Auto {}
class C implements AutoInterface {
state = 1
// private state2 = 2;
protected state3 = 3
}
class Bus extends Auto implements AutoInterface {}