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

自定义支持instanceof的类Proxy取值返回undefined且代理方法未触发

解决Proxy instanceof失效+拦截不触发的问题

我一眼就看出你当前实现的核心问题:你最终返回的实例并不是一个Proxy对象,只是一个被修改了原型链的普通对象——这就是为什么get拦截完全没触发、属性访问返回undefined的原因。虽然你通过合并原型和属性让它过了instanceof,但本质上和Proxy的拦截功能完全脱钩了。

核心思路梳理

要同时满足你的两个核心需求,得抓住两个关键点:

  1. 让实例能通过TargetClass instanceof校验:需要让Proxy的原型链指向TargetClass的原型,让instanceof的判断逻辑能走到目标类的原型链上
  2. 保留Proxy的拦截功能:必须让最终返回的实例就是Proxy对象,所有属性/方法访问都经过拦截器

修复后的ClassProxy实现

这里我重新写了一个简洁且正确的版本,核心是直接把TargetClass的实例作为Proxy的目标对象,同时修正Proxy的原型链:

function ClassProxy(TargetClass, proxyHandler) {
  // 定义中间类,继承自目标类,保证原型链基础
  class ProxyWrapper extends TargetClass {
    constructor(...args) {
      // 先创建目标类的真实实例,作为Proxy的拦截目标
      const targetInstance = super(...args);
      // 创建Proxy,绑定目标实例和自定义拦截器
      const proxy = new Proxy(targetInstance, proxyHandler);
      // 修正Proxy的原型,让它指向中间类的原型(即目标类的子类原型)
      Object.setPrototypeOf(proxy, ProxyWrapper.prototype);
      return proxy;
    }
  }

  // 修正中间类的构造器指向,确保原型链逻辑正确
  Object.defineProperty(ProxyWrapper.prototype, 'constructor', {
    value: ProxyWrapper,
    writable: true,
    configurable: true
  });

  return ProxyWrapper;
}

验证你的测试场景

用你原来的MyClass测试,完全符合预期:

let MyClass = class {
    constructor(myClassName) {
        console.log("Constructed MyClass! myClassName: "+myClassName)
        this.name = myClassName
    }
}

let Haha = ClassProxy(MyClass, {
    get(obj, key) {
        console.log("Intercepted '"+key+"'!")
        return Reflect.get(obj, key)
    }
})

let hahaInstance = new Haha("test")
console.log(hahaInstance.name) // 输出"test",同时打印"Intercepted 'name'!"
console.log(hahaInstance instanceof MyClass) // 输出true

适配你的Creep游戏场景

针对你原来的游戏开发需求,用这个ClassProxy可以直接替换你的代码,完美解决instanceof失效和拦截不触发的问题:

const creepAPI = {
    moveTo: function() {
        console.log("使用优化后的moveTo方法");
        // 这里写你的自定义优化逻辑
    }
}

// 用ClassProxy包装原生Creep类
const WrappedCreep = ClassProxy(Creep, {
    get(realCreep, key) {
        console.log("访问属性/方法:"+key)
        // 优先返回自定义API,同时绑定真实实例上下文
        if (creepAPI[key]) {
            return creepAPI[key].bind(realCreep);
        }
        return Reflect.get(realCreep, key)
    }
})

// 使用方式和原生Creep完全一致
const myCreep = new WrappedCreep(otherCreep.id);
console.log(myCreep instanceof Creep); // 输出true
myCreep.moveTo(); // 调用自定义的优化moveTo方法

为什么这个方案能行?

  1. instanceof生效:中间类ProxyWrapper继承自TargetClass,我们把Proxy的原型设为ProxyWrapper.prototype,所以instanceof会沿着原型链找到TargetClass的原型,判断逻辑完全正常。
  2. 拦截功能正常:最终返回的实例就是Proxy对象,所有属性/方法访问都会经过你传入的handler拦截器。
  3. 上下文正确:自定义API方法通过bind(realCreep)绑定了真实实例的上下文,确保调用时this指向正确的游戏实体。

内容的提问来源于stack exchange,提问作者Hexcede

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:09:40