如何解决每次在TypeScript中调用静态类方法时如何调用静态方法?
我创建了一个单例(抽象)类,它需要在使用大多数方法之前初始化一些数据。这是该类的示例:
abstract class MyClass {
private static initialize(): void {
// do stuff
}
public static doStuff1(param1: string): string {
MyClass.initialize();
// do stuff
return 'stuff1';
}
public static doStuff2(param2: string[]): string[] {
MyClass.initialize();
// do stuff
return ['stuff2'];
}
}
有没有办法避免在每个方法上添加这些 initialize()
调用?我正在考虑使用装饰器并发现这个相关问题:Typescript | Call a function every time a function is called
不幸的是,它使用的是旧式装饰器格式,至少这是我遇到的错误:
Syntax error - Support for the experimental syntax 'decorators-legacy' isn't currently enabled
我试图使用 stage 2 proposal 找到等效的格式,但也许有更好的选择?
解决方法
(通常不鼓励使用单身人士,但由于我不知道您的用例,我假设您有充分的理由使用它们并且不会考虑替代品)。
为了解决您的问题,您可以使用一个小包装实用程序来装饰您的函数:
const wrap = <T extends (...args: any[]) => any>(func: T): T =>
<T>((...args: any[]) => {
// Do something before every function here...
return func(...args);
});
然后你可以像这样定义你的函数:
abstract class MyClass {
public static doStuff1 = wrap((param1: string): string => {
// do stuff
return 'stuff1';
});
}
函数 doStuff1
现在保证在执行自己的代码之前总是先执行 wrap
中的代码。
这种方法的问题在于您无法访问 MyClass
的私有状态或函数,而这可能是可取的。您可以在每次包装时传递对该方法的引用,但与在每个函数的开头调用它相比,您的情况并没有好多少。
更好的方法:非静态单例
如果您无论如何都在使用单例,则最好以非静态方式实现它,并获得保证一次免费初始化的好处:
class MyClass {
private static instance?: MyClass;
static getInstance = (): MyClass =>
(MyClass.instance = MyClass.instance ?? new MyClass());
private constructor() {
// Do your initialization
console.log("initializing");
}
doStuff1() {
// do stuff
console.log("doing stuff 1");
}
doStuff2() {
// do stuff
console.log("doing stuff 2");
}
}
MyClass.getInstance().doStuff1();
// Output:
// initializing
// doing stuff 1
MyClass.getInstance().doStuff1();
MyClass.getInstance().doStuff2();
// Output:
// doing stuff 1
// doing stuff 2
请注意,从上面的输出中,初始化只调用一次,这(根据您的问题判断)似乎是所需的行为。
,我同意 soimons 的回答,因为它鼓励更简洁的代码。不过,您可以使用代理对象来包装您的抽象类,以便您的调用感觉就像您在使用静态单例一样。
我不确定这是否有副作用,但它似乎可以满足您的需求。
_MyClass.ts
abstract class _MyClass {
private static count:number = 0;
private static initialize(): void {
console.log('initialized'+_MyClass.count++);
}
private static doStuff1(param1: string): string {
return 'stuff1';
}
private static doStuff2(param2: string[]): string[] {
return ['stuff2'];
}
public static handler2 = {
get: function(target:any,prop:Function) {
_MyClass.initialize();
return Reflect.get(target,prop);
}
};
}
const MyClass = new Proxy(_MyClass,_MyClass.handler2);
export {MyClass};
index.ts
import { MyClass } from "./_MyClass"
alert(MyClass.doStuff1())
以上代码将产生以下结果:
[LOG]: "initialized0"
[LOG]: "stuff1"
[LOG]: "initialized1"
[LOG]: ["stuff2"]
,
如果这对任何人有帮助,我最终选择了一条更简单的路线,基本上是导出一个非静态类的实例。所以它不再是一个真正的单例,这意味着没有什么能阻止更多实例的初始化,但真的没有意义(除了测试)这样做。
class MyClass {
private prop1: string[];
private prop2: string;
constructor(): {
// load data into the object
this.prop1 = ['a','b'];
this.prop2 = 'c';
}
public getProp1(param: string[]): string[] {
return this.prop1;
}
public getProp2(param: string): string {
return this.prop2;
}
}
const myClass = new MyClass();
export default myClass;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。