You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:53:10