带有默认 属性 值的 Typescript 混合(派生自新的 MyClass)
Typescript mixins with default property values (derived from new MyClass)
我正在 Typescript 中试验一些 mixin,并且已经掌握了使用几种不同方法构建 mixin 的基础知识。在所有这些中,我都遇到了同样的错误。
这是我的 mixin class:
export class OnDestroyMixin implements OnDestroy {
public destroyStream: Subject<void> = new Subject();
ngOnDestroy(): void {
console.log(`on destroy from mixin`);
this.destroyStream.next();
this.destroyStream.complete();
}
}
并且每当调用 on destroy 函数时(在它被混合到另一个 class 中)时 this.destroyStream
不存在所以我得到一个 Cannot read property 'next' of undefined
错误。
我考虑过在构造函数中设置它,但我不确定构造函数在 mixin 中是如何工作的...
我认为这应该是可能的。
我目前使用的mixin方法是mixin装饰器:
export function Mixin(baseCtors: Function[]) {
return function (derivedCtor: Function) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
const descriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name);
if (name === 'constructor')
return;
if (descriptor && (!descriptor.writable || !descriptor.configurable || !descriptor.enumerable || descriptor.get || descriptor.set)) {
Object.defineProperty(derivedCtor.prototype, name, descriptor);
} else {
derivedCtor.prototype[name] = baseCtor.prototype[name];
}
});
});
};
}
我从网上的某个地方复制的,但正如我所说,我尝试了几种不同的方法,这些方法基本上都是将属性从一个原型复制到另一个原型。
此问题的根本原因是,当您在 class 上定义 属性 值时,它被转换为 JavaScript this value is set in the constructor。上面的 mixin 代码特别忽略了构造函数。真正的解决方案是将 2 个 class 构造函数合并在一起。
Typescript 中似乎有两种不同的混合方法。方法类似于我的问题中的方法,我们遍历原型属性并将它们从一个 class 复制到另一个和另一个我们简单地 return a new class that extends the original:
function Flies<TBase extends Constructor>(Base: TBase) {
return class extends Base {
fly() {
alert('Is it a bird? Is it a plane?');
}
};
}
我原以为我不能在 angular 中使用它,因为它是 returns 一个新的 class 的函数,但正如所展示的那样完全有可能 here:
class SourceClass{}
@Component({
selector: 'some-selector',
templateUrl: './some-selector.html',
styleUrls: ['./some-selector.scss']
})
export class SampleMixedClass extends Flies(SourceClass) {}
如我之前的回答所述,问题是 属性 的值是在 mixin class 的构造函数中设置的,而在 mixin 装饰器中忽略了构造函数。
另一种解决方法是不在构造函数中设置 属性 值,而是用 getter 和 setter 定义 属性:
export class OnDestroyMixin implements OnDestroy {
private _destroyStream: Subject<boolean>;
public get destroyStream(): Subject<boolean>{
let stream = this._destroyStream;
if(stream == null){
stream = new Subject<boolean>();
this._destroyStream = stream;
}
return stream;
}
public ngOnDestroy(): void {
this.destroyStream.next();
this.destroyStream.complete();
}
}
事实上,在这种情况下不需要 setter,因为只读值很有用。因为我们使用的是 getter 这不是正常的 属性 并且未在构造函数中设置。相反,我们定义了一个 属性 和一个 getter 函数。这是在 mixin 装饰器中复制的。
我正在 Typescript 中试验一些 mixin,并且已经掌握了使用几种不同方法构建 mixin 的基础知识。在所有这些中,我都遇到了同样的错误。
这是我的 mixin class:
export class OnDestroyMixin implements OnDestroy {
public destroyStream: Subject<void> = new Subject();
ngOnDestroy(): void {
console.log(`on destroy from mixin`);
this.destroyStream.next();
this.destroyStream.complete();
}
}
并且每当调用 on destroy 函数时(在它被混合到另一个 class 中)时 this.destroyStream
不存在所以我得到一个 Cannot read property 'next' of undefined
错误。
我考虑过在构造函数中设置它,但我不确定构造函数在 mixin 中是如何工作的...
我认为这应该是可能的。
我目前使用的mixin方法是mixin装饰器:
export function Mixin(baseCtors: Function[]) {
return function (derivedCtor: Function) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
const descriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name);
if (name === 'constructor')
return;
if (descriptor && (!descriptor.writable || !descriptor.configurable || !descriptor.enumerable || descriptor.get || descriptor.set)) {
Object.defineProperty(derivedCtor.prototype, name, descriptor);
} else {
derivedCtor.prototype[name] = baseCtor.prototype[name];
}
});
});
};
}
我从网上的某个地方复制的,但正如我所说,我尝试了几种不同的方法,这些方法基本上都是将属性从一个原型复制到另一个原型。
此问题的根本原因是,当您在 class 上定义 属性 值时,它被转换为 JavaScript this value is set in the constructor。上面的 mixin 代码特别忽略了构造函数。真正的解决方案是将 2 个 class 构造函数合并在一起。
Typescript 中似乎有两种不同的混合方法。方法类似于我的问题中的方法,我们遍历原型属性并将它们从一个 class 复制到另一个和另一个我们简单地 return a new class that extends the original:
function Flies<TBase extends Constructor>(Base: TBase) {
return class extends Base {
fly() {
alert('Is it a bird? Is it a plane?');
}
};
}
我原以为我不能在 angular 中使用它,因为它是 returns 一个新的 class 的函数,但正如所展示的那样完全有可能 here:
class SourceClass{}
@Component({
selector: 'some-selector',
templateUrl: './some-selector.html',
styleUrls: ['./some-selector.scss']
})
export class SampleMixedClass extends Flies(SourceClass) {}
如我之前的回答所述,问题是 属性 的值是在 mixin class 的构造函数中设置的,而在 mixin 装饰器中忽略了构造函数。
另一种解决方法是不在构造函数中设置 属性 值,而是用 getter 和 setter 定义 属性:
export class OnDestroyMixin implements OnDestroy {
private _destroyStream: Subject<boolean>;
public get destroyStream(): Subject<boolean>{
let stream = this._destroyStream;
if(stream == null){
stream = new Subject<boolean>();
this._destroyStream = stream;
}
return stream;
}
public ngOnDestroy(): void {
this.destroyStream.next();
this.destroyStream.complete();
}
}
事实上,在这种情况下不需要 setter,因为只读值很有用。因为我们使用的是 getter 这不是正常的 属性 并且未在构造函数中设置。相反,我们定义了一个 属性 和一个 getter 函数。这是在 mixin 装饰器中复制的。