ES6 Proxy 应用场景 -4
一、核心应用场景
1. 属性访问跟踪
场景:记录对象属性的读取/修改记录
实现:
const trackable = (obj) => new Proxy(obj, {
get(target, key) {
console.log(`[GET] ${key}`)
return Reflect.get(target, key)
},
set(target, key, value) {
console.log(`[SET] ${key} = ${value}`)
return Reflect.set(target, key, value)
}
})
// 使用
const user = trackable({ name: 'Alice' })
user.name // 控制台输出 [GET] name
user.age = 30 // 控制台输出 [SET] age = 30
2. 属性隐藏
场景:实现私有属性(约定以 _ 开头)
实现:
const createPrivateProxy = (obj) => new Proxy(obj, {
has(target, key) {
if (key.startsWith('_')) return false
return key in target
},
ownKeys(target) {
return Reflect.ownKeys(target).filter(k => !k.startsWith('_'))
}
})
// 使用
const data = createPrivateProxy({
public: 'visible',
_secret: 'hidden'
})
console.log('_secret' in data) // false
console.log(Object.keys(data)) // ["public"]
3. 属性验证
场景:强制数据类型校验
实现:
const validated = (schema) => ({
set(target, key, value) {
if (schema[key] && typeof value !== schema[key]) {
throw new Error(`Invalid type for ${key}`)
}
return Reflect.set(target, key, value)
}
})
const userProxy = new Proxy({}, validated({
age: 'number',
name: 'string'
}))
userProxy.age = 30 // 正常
userProxy.name = 123 // 抛出错误
4. 函数参数验证
场景:验证函数参数类型
实现:
const validateArgs = (fn, check) => new Proxy(fn, {
apply(target, thisArg, args) {
args.forEach((arg, i) => {
if (typeof arg !== check[i]) {
throw new Error(`参数 ${i+1} 类型错误`)
}
})
return Reflect.apply(target, thisArg, args)
}
})
// 使用
const sum = validateArgs(
(a, b) => a + b,
['number', 'number']
)
sum(1, 2) // 3
sum('1', 2) // 报错
5. 数据绑定
场景:DOM 自动同步更新
实现:
const bindDOM = (selector) => {
const el = document.querySelector(selector)
return new Proxy({}, {
set(target, key, value) {
el.textContent = value
return Reflect.set(target, key, value)
}
})
}
// 使用
const title = bindDOM('#title')
title.text = 'Hello Proxy!' // 自动更新 DOM
二、进阶应用场景
1. 缓存代理
场景:缓存函数计算结果
const createCacheProxy = (fn) => {
const cache = new Map()
return new Proxy(fn, {
apply(target, thisArg, args) {
const key = JSON.stringify(args)
if (cache.has(key)) {
console.log('返回缓存结果')
return cache.get(key)
}
const result = Reflect.apply(target, thisArg, args)
cache.set(key, result)
return result
}
})
}
// 使用
const heavyCalc = (n) => n * 2
const cachedCalc = createCacheProxy(heavyCalc)
cachedCalc(5) // 计算
cachedCalc(5) // 控制台显示"返回缓存结果"
2. 权限控制
场景:基于角色限制访问
const createGuard = (obj, role) => new Proxy(obj, {
get(target, key) {
if (key === 'adminData' && role !== 'admin') {
throw new Error('权限不足')
}
return Reflect.get(target, key)
}
})
// 使用
const data = createGuard({
public: 'info',
adminData: 'secret'
}, 'user')
console.log(data.public) // "info"
console.log(data.adminData) // 报错
3. 自动 ORM 映射
场景:数据库字段动态映射
class UserModel {
constructor(data) {
return new Proxy(data, {
get(target, key) {
if (key === 'fullName') {
return `${target.firstName} ${target.lastName}`
}
return Reflect.get(target, key)
}
})
}
}
// 使用
const user = new UserModel({
firstName: 'John',
lastName: 'Doe'
})
console.log(user.fullName) // "John Doe"
三、创新应用场景
1. 模式匹配
场景:实现类似 Rust 的模式匹配
const match = (pattern) => new Proxy({}, {
get(_, key) {
return (value) => {
if (typeof pattern === 'function' ? pattern(value) : pattern === value) {
return { [key]: value }
}
return null
}
}
})
// 使用
const check = match({
status: 200,
data: (d) => d.length > 0
})
const res = { status: 200, data: [1,2,3] }
console.log(check.success(res)) // { success: res }
2. 不可变数据
场景:创建不可变对象
const immutable = (obj) => new Proxy(obj, {
set() { throw new Error('不可修改') },
deleteProperty() { throw new Error('不可删除') }
})
// 使用
const config = immutable({ key: 'abc123' })
config.key = 'new' // 抛出错误
3. 链式调用优化
场景:优化 Lodash 式链式调用
const chainable = (obj) => new Proxy({}, {
get(_, method) {
return (...args) => {
obj = method === 'value' ? obj : obj[method](...args)
return chainable(obj)
}
}
})
// 使用
const _ = chainable([1,2,3])
.filter(x => x > 1)
.map(x => x * 2)
.value()
console.log(_) // [4,6]
四、Proxy 应用全景图
graph LR
A[Proxy 核心应用] --> B[元编程]
A --> C[数据拦截]
A --> D[行为扩展]
B --> B1(调试工具)
B --> B2(DSL实现)
B --> B3(模式匹配)
C --> C1(响应式系统)
C --> C2(数据校验)
C --> C3(访问控制)
D --> D1(链式优化)
D --> D2(缓存代理)
D --> D3(延迟加载)
classDef highlight fill:#f9f,stroke:#333;
class B1,B2,B3,C1,C2,C3,D1,D2,D3 highlight
关键知识点总结
-
陷阱方法选择
根据场景选择正确的拦截器(如数据验证用set,函数拦截用apply) -
Reflect 的必要性
始终使用Reflect方法保持默认行为:// 正确做法 set(target, key, value) { // 自定义逻辑 return Reflect.set(...arguments) } -
性能注意事项
避免深层代理嵌套,对于性能敏感场景使用对象池:const proxyCache = new WeakMap() function createProxy(obj) { if (proxyCache.has(obj)) return proxyCache.get(obj) const proxy = new Proxy(...) proxyCache.set(obj, proxy) return proxy } -
浏览器兼容方案
通过@babel/plugin-proxy实现 IE11 兼容:npm install @babel/plugin-proxy
通过以上案例可以看出,Proxy 为 JavaScript 带来了强大的元编程能力,能够优雅地解决许多传统编程模式难以处理的问题。这些模式不仅提升了代码的可维护性,也为实现复杂系统架构提供了新的可能性。

浙公网安备 33010602011771号