TypeScript Mixin 混入

3,287 阅读2分钟

多继承的毛病

  • TypeScript 不支持多重继承,这意味着一个类只能继承自一个类,因为他会潜在地增加程序的复杂性。
  • 倘若,在支持多继承的环境下,一个子类所继承的两个父类都拥有一个同名的方法,子类在调用父类方法的时候,哪一个父类的方法被调用是不清楚或者说是有歧义的。
// 以下代码为错误代码
class Bat extends WingeAnimal, Mammal {
    // ...
}

混入介绍

  • 但是,有时候,我们会认为声明一个同时继承两个或多个类的类是一个好的想法。
  • 为了避免多继承实现中潜在的危险,我们可以使用混入(又称混合,Mixin)特性。
  • 首先是两个基类
class Mammal {
    breathe() : string {
        return "I'm alive!";
    }
}

class WingedAnimal {
    fly() : string {
        return "I can fly!";
    }
}
  • 下面是子类,使用 implements 替代 extends,因此继承自的类仍需要实现,这里只是占坑
class Bat implements Mammal, WingedAnimal {
    breathe: () => string;
    fly: () => string;
}

使用以下函数,将基类的方法实现/复制到子类中

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        // 即是将“父类”原型对象中的属性,复制到子类的原型对象中
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            if (name !== 'constructor') {
                derivedCtor.prototype[name] = baseCtor.prototype[name];
            }
        });
    });
}
// 实现子类函数
applyMixins(bat, [Mammal, WingedAnimal]);

混入的限制

  1. 只能在继承树上继承一级的方法和属性。因为编译过后,在 JavaScript 中,父类的方法是在父类的原型对象中,子类的原型对象上找不到父类的方法。
  2. 如果两个或更多的父类包含了同名的方法,那么只会继承传入 applyMixins 函数中 baseCtor 数组中最后一个类中的该方法。