JS Proxy的getter属性内部如何访问代理目标对象?
核心原因
直接在Proxy handler里写get myGetter()拿不到target,根本原因是handler本身只是存储Proxy配置的普通对象,它自己的getter运行时只能拿到handler对象的this,根本碰不到Proxy每次读取属性时传给get捕获器的target参数——这是JS词法作用域的固有规则,不是写法错误。
实现方法
要实现两类逻辑(访问即返回计算值的getter、访问返回可传参函数引用的普通方法),有两种非常干净的写法,不需要硬编码属性名,也不用额外维护复杂分组:
方案1:标记法(灵活度最高,推荐)
用一个不会和业务属性重名的Symbol给需要自动执行的getter打标记,get捕获器里判断到标记就直接传入target执行返回结果,没标记就返回绑定了target的函数引用即可。后续新增方法只需要决定加不加标记,不用修改核心判断逻辑:
const IS_AUTO_GETTER = Symbol('auto-run-getter'); const myProxy = new Proxy( { test: 2 }, { get(target, prop, receiver) { if (Object.hasOwn(this, prop) && typeof this[prop] === 'function') { const handlerVal = this[prop]; // 标记为getter的属性访问即执行 if (handlerVal[IS_AUTO_GETTER]) return handlerVal(target); // 普通方法返回可传参的函数引用 return (...args) => handlerVal(target, ...args); } // 目标对象自有属性走原生逻辑,保留原有getter、this绑定行为 return Reflect.get(target, prop, receiver); }, // 定义自动执行的getter,加上标记即可 myGetter: (() => { const fn = target => ++target.test; fn[IS_AUTO_GETTER] = true; return fn; })(), // 普通方法无需标记 myFunc(target, val) { return target.test * val; } } ); // 测试效果 console.log("myFunc(3)结果:", myProxy.myFunc(3)); // 输出6 console.log("初始test值:", myProxy.test); // 输出2 console.log("myGetter值:", myProxy.myGetter); // 输出3,无需加括号调用 console.log("修改后test值:", myProxy.test); // 输出3
方案2:闭包原生getter写法(最贴近原生getter语法)
如果坚持要用get xxx()的原生访问器语法,可以把target和自定义属性都放在IIFE闭包内,getter可以直接通过闭包引用拿到target,完全不需要额外传参:
const myProxy = (() => { // 目标对象放在闭包内部 const target = { test: 2 }; // 此处定义的是真正的原生getter,可直接访问闭包内的target const customGetters = { get myGetter() { return ++target.test; } }; // 普通方法也存在闭包内 const customMethods = { myFunc(val) { return target.test * val; } }; return new Proxy(target, { get(t, prop, receiver) { if (prop in customGetters) return customGetters[prop]; if (prop in customMethods) return customMethods[prop].bind(customMethods); return Reflect.get(t, prop, receiver); } }); })(); // 测试效果和方案1完全一致 console.log("myFunc(3)结果:", myProxy.myFunc(3)); console.log("初始test值:", myProxy.test); console.log("myGetter值:", myProxy.myGetter); console.log("修改后test值:", myProxy.test);
这个写法的局限是target固定在闭包内,不适合需要后续动态替换Proxy target的场景,若Proxy创建后target不会变更,用起来最顺手。
内容的提问来源于stack exchange,提问作者vanowm
相关产品推荐
相关产品推荐

