编写TypeScript装饰器:始终将类方法绑定至this
嘿,我看你正在折腾一个能自动绑定类方法this到实例的装饰器,这个需求太懂了——每次写类都要手动给方法绑this真的烦!你的代码已经有了开头,我来帮你补全并把逻辑说清楚~
完整的装饰器实现
function LockThis<T extends { new(...args: any[]): {} }>(constructor: T) { // 创建继承自原类的子类 const locker = class extends constructor { constructor(...args: any[]) { super(...args); // 获取原类的原型对象 const proto = constructor.prototype; // 遍历原型上的所有属性 Object.getOwnPropertyNames(proto).forEach(key => { // 跳过构造函数本身 if (key === 'constructor') return; const descriptor = Object.getOwnPropertyDescriptor(proto, key); if (!descriptor) return; // 处理普通函数方法:绑定this到当前实例 if (typeof descriptor.value === 'function') { this[key] = descriptor.value.bind(this); } // 扩展处理getter/setter(如果需要的话) if (typeof descriptor.get === 'function') { Object.defineProperty(this, key, { get: descriptor.get.bind(this) }); } if (typeof descriptor.set === 'function') { Object.defineProperty(this, key, { set: descriptor.set.bind(this) }); } }); } }; // 把原类的静态属性/方法复制到子类,避免装饰后丢失 Object.assign(locker, constructor); return locker; }
代码逻辑解释
- 我们创建了一个继承自原类的子类
locker,这样能保留原类的所有功能,同时添加绑定逻辑。 - 在子类构造函数里,先调用
super(...args)初始化原类实例,然后遍历原类原型上的所有属性。 - 跳过
constructor本身,只处理函数类型的成员:把每个方法(包括getter/setter)都通过bind绑定到当前实例,这样不管你怎么调用这个方法(比如把它抽出来单独调用),this都始终指向类实例。 - 最后用
Object.assign把原类的静态属性复制到子类,确保装饰后的类不会丢失原有的静态方法或属性。
使用示例
@LockThis class User { username = 'Alice'; sayHi() { console.log(`Hi, I'm ${this.username}!`); } get greeting() { return `Hello from ${this.username}`; } } const user = new User(); // 把方法抽出来单独调用,this依然正确指向实例 const sayHi = user.sayHi; sayHi(); // 输出 "Hi, I'm Alice!" // getter也能正常工作 console.log(user.greeting); // 输出 "Hello from Alice"
一些注意点
- 对于类里的箭头函数属性(比如
sayHi = () => {}),它们本身就已经绑定了this,装饰器不会对它们产生影响,也不会有冲突。 - 如果你的类有动态添加的实例方法(不是在原型上定义的),这个装饰器不会处理它们,你可能需要手动绑定或者调整装饰器逻辑。
- 这个实现会在实例上重新定义方法,覆盖原型上的方法,所以如果有方法是不可写的,可能需要额外处理
descriptor.writable属性。
内容的提问来源于stack exchange,提问作者user358089
相关产品推荐
相关产品推荐

