Proxy vs Reflect
我们可以从 3W1H(What、Why、When、How)角度来系统性地理解 JavaScript 中的 Proxy
和 Reflect
:
🧠 1. What 是什么?
🔹 Proxy
Proxy
是 ES6 引入的一个构造函数,用于创建一个对象的代理,可以在对该对象进行操作时(如读写属性、函数调用、构造等)进行拦截并自定义行为。
js
const proxy = new Proxy(target, handler)
其中 target
是被代理的对象,handler
是定义拦截行为的对象。
🔹 Reflect
Reflect
是一个内置对象,它提供了一组用于操作对象的静态方法,对象的底层操作(如属性读取、设置、删除、函数调用等)都可以通过 Reflect
来完成,通常和 Proxy
一起使用。
js
Reflect.get(target, property, receiver)
🎯 2. Why 为什么需要?
🔹 Proxy 的目的
- 自定义对象操作行为(如属性访问、赋值、函数调用等)
- 实现数据绑定(如 Vue3 的响应式系统)
- 实现访问控制、安全校验
- mock 数据、拦截日志打印等
🔹 Reflect 的目的
- 提供更一致的对象操作 API(如替代
Object.defineProperty
、obj[prop] = value
等) - 与 Proxy 配合使用,实现默认行为更方便(避免手动重复实现目标行为)
- 提高代码可读性,像函数一样使用原生行为
🕒 3. When 什么时候使用?
场景 | 使用 Proxy | 使用 Reflect |
---|---|---|
想拦截对象的读写行为 | ✅ | ❌ |
想优雅实现默认行为 | ✅ (配合 Reflect) | ✅ |
想动态添加验证、权限控制等 | ✅ | ❌ |
替代旧的对象操作方法(如 Object.defineProperty) | ❌ | ✅ |
编写通用库或框架底层封装 | ✅ | ✅ |
⚙️ 4. How 如何使用?
示例:使用 Proxy 和 Reflect 拦截属性访问
js
const target = { name: 'Flash', age: 30 }
const proxy = new Proxy(target, {
get(target, key, receiver) {
console.log(`访问属性: ${key}`)
return Reflect.get(target, key, receiver) // 保留原始行为
},
set(target, key, value, receiver) {
console.log(`设置属性: ${key} = ${value}`)
return Reflect.set(target, key, value, receiver) // 保留原始行为
}
})
proxy.name // 控制台输出: 访问属性: name
proxy.age = 31 // 控制台输出: 设置属性: age = 31
✅ 总结对比
对比项 | Proxy | Reflect |
---|---|---|
类型 | 构造函数 | 内置对象 |
功能 | 拦截对象行为,定义自定义逻辑 | 执行默认对象操作 |
用法 | 创建代理对象,对目标对象包装 | 提供与 Proxy 拦截方法对应的原始操作 |
常见用途 | 数据劫持、校验、封装逻辑 | 配合 Proxy 保留默认行为 |
ES 版本 | ES6 | ES6 |