如何让每次调用返回的匿名函数为同一实例?
没问题!咱们来一步步解决这个问题——先看你给出的代码:
public example() { return (): string => { return 'hello world'; }; } let a = example(); let b = example(); console.log(a === b); // 输出 false
每次调用example()都会创建一个全新的箭头函数实例,所以a和b指向不同的内存引用,自然会打印false。要实现复用同一个函数实例,同时保证隔离性(不同调用场景下状态/行为互不干扰),可以用下面几种方式,完全不用把函数挂到this上:
1. 类级/模块级缓存纯函数实例
如果你的匿名函数是纯函数(就像例子里这样,没有依赖外部可变状态,输出完全固定),那最简单的方式就是提前把这个函数定义成一个私有常量,每次example()直接返回这个常量的引用:
class YourClass { // 提前定义好要复用的函数实例,类内所有实例共享 private static readonly cachedHelloFn = (): string => { return 'hello world'; }; public example() { return YourClass.cachedHelloFn; } } const instance = new YourClass(); let a = instance.example(); let b = instance.example(); console.log(a === b); // 输出 true
这种方式下,所有example()调用都会返回同一个函数实例,而且因为是纯函数,完全不存在隔离性问题——不管调用多少次,它的行为都是固定的,不会有任何状态互相干扰的情况。
2. 闭包缓存+参数隔离带状态的函数
如果你的匿名函数需要依赖隔离的可变状态(比如不同调用需要绑定不同的用户信息、上下文数据),那不能直接复用同一个函数实例(否则状态会被共享),但可以复用函数逻辑,通过闭包或参数传递来绑定独立状态:
比如我们可以用一个模块级的缓存Map,根据不同的输入参数来复用对应的函数实例:
// 模块级缓存,用来存储不同参数对应的函数实例 const messageFnCache = new Map<string, () => string>(); class YourClass { public example(name: string) { // 检查缓存里有没有对应name的函数,没有就创建并缓存 if (!messageFnCache.has(name)) { messageFnCache.set(name, () => `hello ${name}`); } return messageFnCache.get(name)!; } } const instance = new YourClass(); let a = instance.example('Alice'); let b = instance.example('Alice'); console.log(a === b); // 输出 true(相同参数复用同一实例) let c = instance.example('Bob'); console.log(a === c); // 输出 false(不同参数对应不同实例,状态隔离)
这样一来,相同参数的调用会复用同一个函数实例,不同参数的调用则会使用独立的实例,既做到了函数复用,又保证了不同场景下的状态完全隔离。
3. 实例级闭包缓存
如果不想用类静态属性或模块级变量,也可以在类初始化时用IIFE创建一个闭包来缓存函数实例:
class YourClass { // 用IIFE在实例初始化时就创建好函数实例,之后每次调用都返回它 public example = (() => { const reusableFn = (): string => { return 'hello world'; }; return () => reusableFn; })(); } const instance = new YourClass(); let a = instance.example(); let b = instance.example(); console.log(a === b); // 输出 true
这种方式下,每个类实例会有自己的缓存函数(如果需要实例级隔离的话),但同一个实例的多次example()调用都会返回同一个函数引用,同样满足你的需求。
总结一下:如果是纯函数,直接缓存实例即可;如果需要带隔离状态,就根据参数缓存对应的实例,用闭包绑定独立状态,完全不用把函数挂到this属性上。
内容的提问来源于stack exchange,提问作者user1031569

