必须用 reflect 而不是直接访问 target[prop],因为后者会绕过原型链上的 getter/setter,且在 receiver 不一致时行为异常;reflect.get/set 能准确复现引擎原生行为并正确处理 this 绑定。

Proxy 结合 Reflect.get 和 Reflect.set 实现日志记录,核心在于:用 Proxy 拦截读写行为,再在拦截器中调用 Reflect 方法执行原始操作,同时插入 console.log 或其他日志逻辑。
为什么必须用 Reflect 而不是直接访问 target[prop]?
直接写 target[propKey] 或 target[propKey] = value 会绕过原型链上的 getter/setter,也可能在某些边界情况(如 receiver 不一致)下行为异常。Reflect.get/set 是规范定义的底层操作,能准确复现 JavaScript 引擎原本的行为,并天然支持 receiver 参数,确保 this 绑定正确。
基础日志代理的写法
下面是一个可直接运行的最小示例:
const target = { name: 'Alice', score: 95 };
const handler = {
get(target, propKey, receiver) {
console.log(`[GET] ${propKey}`);
return Reflect.get(target, propKey, receiver);
},
set(target, propKey, value, receiver) {
console.log(`[SET] ${propKey} = ${value}`);
return Reflect.set(target, propKey, value, receiver);
}
};
const proxy = new Proxy(target, handler);
proxy.name; // [GET] name
proxy.score = 98; // [SET] score = 98
增强日志的实用技巧
- 记录时间戳:
console.log(`[${new Date().toISOString()}] [GET] ${propKey}`) - 区分是否为自有属性:
Object.prototype.hasOwnProperty.call(target, propKey) ? 'own' : 'inherited' - 捕获错误并记录:
try { ... } catch (e) { console.error('[ERROR in GET]', propKey, e); throw e; } - 对特定属性静默(不打日志):
if (propKey === 'internal') return Reflect.get(...);
注意 receiver 的实际影响
receiver 是触发 get/set 的那个对象(通常是 proxy 本身),它会影响 this 指向。比如目标对象里有 getter:get fullName() { return this.name + ' Doe'; },若不用 receiver,this 会指向 target,导致 this.name 取不到值;而 Reflect.get(target, 'fullName', proxy) 能保证 this 正确绑定到 proxy,从而让 getter 正常工作。











