ts的混入
刚接触混入(mixins)
,很容易跟合并(merge)
搞混淆.看了官方文档的解释才弄明白
merge
For the purposes of this article, “declaration merging” means that the compiler merges two separate declarations declared with the same name into a single definition. This merged definition has the features of both of the original declarations. Any number of declarations can be merged; it’s not limited to just two declarations.
merga是将名字相同的声明合并到1个definition里,然后这个definition拥有所有declaration的特征.
typeScript只能单继承,不能多继承。为了实现多继承的效果,ts提供了一些写法.❗mixins不是功能,而是概念.
“Real” Mixins with JavaScript Classes
A mixin is an abstract subclass; i.e. a subclass definition that may be applied to different superclasses to create a related family of modified classes.
Gilad Bracha and William Cook, Mixin-based Inheritance
下面给出如何在typeScript中实现mixins的写法.
单继承mixins
TypeScript: Documentation - Mixins的例子
class Sprite {
name = "";
x = 0;
y = 0;
constructor(name: string) {
this.name = name;
}
}
// To get started, we need a type which we'll use to extend
// other classes from. The main responsibility is to declare
// that the type being passed in is a class.
type Constructor = new (...args: any[]) => {};
// This mixin adds a scale property, with getters and setters
// for changing it with an encapsulated private property:
function Scale<TBase extends Constructor>(Base: TBase) {
return class Scaling extends Base {
// Mixins may not declare private/protected properties
// however, you can use ES2020 private fields
private _scale = 1;
set scale(scale: number) {
this._scale = scale;
}
get scale(): number {
return this._scale;
}
};
}
// Compose a new class from the Sprite class,
// with the Mixin Scale applier:
const EightBitSprite = Scale(Sprite);
const flappySprite = new EightBitSprite("Bird");
flappySprite.scale = 0.8
// (property) Scaling<typeof Sprite>.scale: number
console.log(flappySprite.scale); // output:0.8
这里给2个function设置了set
和get
修饰符,让scale(scale: number)
和scale()
变成了属性。如果只设置get
那么_scale
就会变成readonly.
2.混入实现多继承
因为typeScript不支持多继承,所以这里要用implements来实现.
class MyName {
name: string
constructor(name: string) {
this.name = name
}
getName(): string {
return this.name
}
}
class MyAge {
age: number
constructor(age: number) {
this.age = age
}
setAge(age: number): void {
this.age = age
}
}
class Jack implements MyName,MyAge{
name: string
getName!: () => string
age: number
setAge!: (age: number) => void
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
因为是implements所以是需要实现class里的属性的.这里我选择不实现所以用!
使其可以为undefined通过编译.
上面的class准备好后下面才是mixins.
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(Jack,[MyName,MyAge])
let jack = new Jack('J4ck',0)
console.log(jack.getName()); // output:J4ck
console.log(jack.age); // output:0
jack.setAge(23)
console.log(jack.age); // output:23
可以看到Jack类获得了MyName和MyAge的所有特征.