类的声明 & 实现
TS为成员属性和构造函数的参数添加了类型注解 run方法默认返回值是void
class Dog {
constructor(name: string) {
this.name = name;
}
name: string;
run() {}
}
构造函数的返回值类型默认会被推断为Dog,即本类
注:
无论是在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的初始化,将提示错误
- 如下代码所示:
```typescript
class Dog {
constructor(name: string) {
} name: string; run() {} }// this.name = name;
console.log(Dog.prototype);
let dog = new Dog(“wangcai”); console.log(dog);
![image.png](https://cdn.nlark.com/yuque/0/2020/png/1544252/1596806211632-21995198-16e6-42b6-97a0-9a8c0ca200b1.png#align=left&display=inline&height=255&margin=%5Bobject%20Object%5D&name=image.png&originHeight=255&originWidth=467&size=34980&status=done&style=shadow&width=467)<br />处理:
```typescript
// 初始值
{
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 {}