模仿文档中给出的类继承的例子
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,小写的英文代表该类实例化的对象
子类通过重写子类的原型对象,将子类的原型对象指向超类的实例,达到继承的目的。
现在有一点疑问,
实例属性和实例方法是没有存放到原型对象,为什么子类可以访问父类的实例属性和实例方法
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.
有空再看构造函数