被装饰的单例类instanceof判断失效问题排查
解决单例装饰器导致
instanceof失效的问题 你的问题出在装饰器返回了一个与原类完全独立的包装类,而实际创建的实例是原类的实例,两者的原型链没有关联,导致instanceof校验失败。
问题根源
当你用@Singleton()装饰TestSingleton后,TestSingleton这个变量已经指向装饰器返回的包装类,而非你最初定义的TestSingleton类。但你的装饰器里是通过new constructor(...)创建原类的实例,这个实例的原型链只和原类绑定,和包装类毫无关系,所以x instanceof TestSingleton(此时TestSingleton是包装类)自然返回false。
修复方案
这里提供两种可靠的修复思路:
方案一:让包装类继承原类
通过extends让包装类继承原类,保证原型链的连续性,同时保留单例逻辑:
interface Type<T = any> extends Function { new (...args: any[]): T; } function Singleton() { let instance: Object; return function <SingletonFunction extends Type>( constructor: SingletonFunction ) { // 让包装类继承原类,确保原型链关联 const WrapperClass = class extends constructor { constructor(...args: any[]) { if (instance) { return instance; } // 调用原类构造函数 super(...args); instance = this; } }; // 保持类名一致,方便调试 Object.defineProperty(WrapperClass, 'name', { value: constructor.name }); return WrapperClass as SingletonFunction; }; }
方案二:重写原类的构造函数(不替换原类引用)
这种方式不会改变TestSingleton的指向,直接修改原类的构造函数实现单例,同时保留原类的所有静态成员和原型链:
interface Type<T = any> extends Function { new (...args: any[]): T; } function Singleton() { return function <SingletonFunction extends Type>( constructor: SingletonFunction ) { let instance: InstanceType<SingletonFunction>; // 保存原构造函数 const originalConstructor = constructor; // 重写构造函数实现单例逻辑 const singletonConstructor = function(...args: any[]) { if (instance) { return instance; } instance = new originalConstructor(...args); // 修正this的原型指向 Object.setPrototypeOf(this, originalConstructor.prototype); return instance; } as unknown as SingletonFunction; // 同步原类的原型、类名和静态成员 singletonConstructor.prototype = originalConstructor.prototype; Object.defineProperty(singletonConstructor, 'name', { value: originalConstructor.name }); Object.assign(singletonConstructor, originalConstructor); return singletonConstructor; }; }
测试验证
用任意一种方案修改后,运行你的测试代码会得到预期结果:
const x = new TestSingleton([1, 2, 3, 4, 5, 6]); const y = new TestSingleton([6, 7, 8, 9, 1]); console.log(x === y); // true console.log(x instanceof TestSingleton); // true
内容的提问来源于stack exchange,提问作者Nilesh Kumar
相关产品推荐
相关产品推荐

