TypeScript-4-类

模仿文档中给出的类继承的例子


class Animal{
myName:string;
constructor(name:string){
	this.myName=name;

}
print(){
	console.log(`我叫${this.myName}`);
}
}
let animal=new Animal('动物');
animal.print();

class Cat extends Animal{

}
let cat =new Cat('猫');
console.log(cat.myName);//猫
cat.print()//我叫猫

当然没有引入新的属性和方法,这个继承也没有意义,那么增加新的属性和方法。

先回顾一下原型链继承(觉得代码太长可以跳过)

class Animal {
	constructor() {
		this.a = 1;
	}
	print() {
		console.log(this.a)
	}
}
Animal.prototype.name = '1';
class Cat extends Animal {
	constructor() {
		super();
	}
	print() {
		console.log(1)
	}
}

var cat = new Cat();
//其中class Cat extends Animal 等价于
// Cat.prototype=new Animal();
//因此Cat的prototype属性指向超类的实例
//函数的prototype包含constructor属性
console.log(Animal.prototype) //{constructor: ƒ, print: ƒ}
//Animal.prototype.constructor里面又有一个prototype
console.log(Animal.prototype.constructor.prototype === Animal.prototype); //true
console.log(Animal.prototype.constructor === Animal); //true
//换言之,Animal.prototype就是原型对象,原型对象里面含有原型属性和原型方法,原型对象中的constructor指向函数本身
//函数本身肯定就有prototype,所以才有这么一长串Animal.prototype.constructor.prototype
var animal1 = new Animal();
console.log(animal1.__proto__)
//函数实例的__proto__属性指向函数的原型对象
console.log(animal1.__proto__ === Animal.prototype) //true

核心就是以下四个布尔表达式

类Cat继承自类Animal,小写的英文代表该类实例化的对象

  1. Animal.prototype.constructor === Animal//原型的constructor指向类本身
  2. animal1.__proto__ === Animal.prototype//实例的__proto__属性指向类的原型,通过这个关系可以访问原型方法和原型属性
  3. cat.__proto__ === Cat.prototype//这个同第二个
  4. Cat.prototype.__proto__ === Animal.prototype//子类原型的__proto__指向超类的原型,因此子类可以访问超类的原型方法和原型属性

 

子类通过重写子类的原型对象,将子类的原型对象指向超类的实例,达到继承的目的。

现在有一点疑问,

实例属性和实例方法是没有存放到原型对象,为什么子类可以访问父类的实例属性和实例方法

cat.__proto__.__proto__ === Animal.prototype

那么cat.__proto__.__proto__.constructor就指向Animal本身。我理解只有对象才能访问类的实例属性和实例方法。

我们测试一下原型链方式能不能访问子类实例属性。

function Animal() {
	this.a = '1';
}
Animal.prototype.a = '2'

function Cat() {}
Cat.prototype = new Animal();
let cat = new Cat();
console.log(cat.a);//1

实例属性会屏蔽原型属性,那么用我们上面所学,能否输出这四个属性?(方法类似)

子类的原型属性 4,实例属性 3

超类的原型属性 2,实例属性 1

function Animal() {
	this.a = '1';
}
Animal.prototype.a = '2';

function Cat() {
	this.a = '3';
}
Cat.prototype = new Animal();
Cat.prototype.a = '4';
let cat = new Cat();
console.log(cat.a); //3
console.log(cat.__proto__.a) //4
console.log(cat.__proto__.__proto__.a) //2

这个超类的实例属性,目前还不知道有什么方法能够访问。

这里的核心就是cat.__proto__ === Cat.prototype

联系对象和类。

还是回到TypeScipt,之所有想到这些是因为文档上的一句话:

我还以为像多态一样可以访问超类的原型方法。但是我上面的套路可以实现。(属性和方法没有本质区别)

接着往下看

public是默认行为

private不能在类外访问

protected子类可以访问,除此之外不能访问

readonly可以访问,除构造函数内不可修改

class Octopus {
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string) {
    }
}

构造函数里,变量用修饰符修饰相当于声明了一个该修饰符修饰的实例属性。

抽象类,如下:

abstract class Animal{
	constructor(public name:string){

	}
	print(): void{
		console.log(`我叫${this.name}`);
	}
	abstract makeVoice():void;
}
class Cat extends Animal{
	constructor(name:string){
		super(name);
	}
	makeVoice():void{
		console.log(`${this.name}喵喵叫`);
	}
	eat():void{
	console.log(`${this.name}吃鱼`);
	}
}
let cat:Cat=new Cat('小猫');
cat.print();
cat.makeVoice();
cat.eat();

文档里有一个错误:方法在声明的抽象类中不存在

这个错误要怎么重现呢,需要将类的声明方式改一下

let cat:Animal=new Cat('小猫');

抽象类不能实例化有点类型protected修饰构造函数,如下

 class Animal{
	protected constructor(public name:string){

	}
	print(): void{
		console.log(`我叫${this.name}`);
	}

}
let animal:Animal=new Animal('动物');

 Constructor of class 'Animal' is protected and only accessible within the class declaration.

有空再看构造函数

你可能感兴趣的:(前端,typescript)