Proxy Basic Usage
ES6 Proxy 的基本用法和常见拦截操作
问题
如何使用 ES6 的 Proxy 创建对象代理,实现对对象操作的拦截?
解答
基本语法
const proxy = new Proxy(target, handler)
// target: 要代理的目标对象
// handler: 定义拦截行为的对象
常用拦截操作
const target = {
name: 'Alice',
age: 25
}
const handler = {
// 拦截属性读取
get(target, prop, receiver) {
console.log(`读取属性: ${prop}`)
return Reflect.get(target, prop, receiver)
},
// 拦截属性设置
set(target, prop, value, receiver) {
console.log(`设置属性: ${prop} = ${value}`)
return Reflect.set(target, prop, value, receiver)
},
// 拦截 in 操作符
has(target, prop) {
console.log(`检查属性: ${prop}`)
return Reflect.has(target, prop)
},
// 拦截 delete 操作
deleteProperty(target, prop) {
console.log(`删除属性: ${prop}`)
return Reflect.deleteProperty(target, prop)
}
}
const proxy = new Proxy(target, handler)
proxy.name // 读取属性: name -> 'Alice'
proxy.age = 30 // 设置属性: age = 30
'name' in proxy // 检查属性: name -> true
delete proxy.age // 删除属性: age
实际应用:数据验证
function createValidator(target, rules) {
return new Proxy(target, {
set(target, prop, value) {
const rule = rules[prop]
if (rule && !rule.validate(value)) {
throw new Error(rule.message)
}
return Reflect.set(target, prop, value)
}
})
}
const user = createValidator({}, {
age: {
validate: v => typeof v === 'number' && v >= 0 && v <= 150,
message: 'age 必须是 0-150 的数字'
},
email: {
validate: v => /^[\w-]+@[\w-]+\.\w+$/.test(v),
message: 'email 格式不正确'
}
})
user.age = 25 // 正常
user.email = 'a@b.com' // 正常
user.age = -1 // Error: age 必须是 0-150 的数字
实际应用:响应式数据
function reactive(obj, callback) {
return new Proxy(obj, {
set(target, prop, value) {
const oldValue = target[prop]
const result = Reflect.set(target, prop, value)
if (oldValue !== value) {
callback(prop, value, oldValue)
}
return result
}
})
}
const state = reactive({ count: 0 }, (prop, newVal, oldVal) => {
console.log(`${prop}: ${oldVal} -> ${newVal}`)
})
state.count++ // count: 0 -> 1
state.count++ // count: 1 -> 2
常用 handler 方法
| 方法 | 拦截操作 |
|---|---|
| get | 读取属性 |
| set | 设置属性 |
| has | in 操作符 |
| deleteProperty | delete 操作 |
| apply | 函数调用 |
| construct | new 操作 |
| getPrototypeOf | Object.getPrototypeOf |
| ownKeys | Object.keys / for…in |
关键点
- Proxy 可以拦截对象的 13 种基本操作
- 配合 Reflect 使用,保持默认行为的同时添加自定义逻辑
- Vue 3 的响应式系统基于 Proxy 实现
- Proxy 是惰性的,只有访问时才触发拦截
- 与 Object.defineProperty 相比,Proxy 可以拦截数组变化和新增属性
目录