为其他对象提供一种代理以控制对这个对象的访问;
直接访问会给使用者或者系统结构带来很多麻烦,在访问此对象时加上一层访问层;
装饰器模式:不能改变原始对象的行为、代理模式:可以改变原始对象的行为(代理和目标都可自行扩展);
常见使用:
const container= document.getElementById('container')
container.addEventListener('click', function (e) {
const target = e.target
if (target.nodeName === 'A') {
// ... do something
}
})
以上为DOM 事件代理( 也叫事件委托 );
正向代理:webpack-dev-server ~ proxy ;
nginx 反向代理、客户端只需要根据服务端给定端口进行访问,而服务端自行判断;
例如、你通过房产中介买房子,中介就是一个代理、你接触到的是中介这个代理,而非真正的房主;
// 户主
class master {
sign() {
console.log('户主签字')
}
}
// 代理
class agent {
constructor() {
this.master = new master()
}
// 签约
sign() {
console.log('按指纹')
console.log('交定金')
console.log('顾客签字')
// ... 限制
this.master.sign()
}
}
const proxy = new agent()
proxy.sign()
例如、明星和经纪人,主办方需要联系经纪人进行签约,使用 proxy
const star = {
name: 'iu',
age: 18,
phone: '****', // 号码
price: 0 // 出场费
}
const min = 100 * 1000 // 最少出场费
// 经纪人
const agent = new Proxy(star, {
get(target, key) {
if (key === 'phone') {
return '13988888888' // 经纪人电话
} else if (key === 'price') {
const now = Reflect.get(target, key)
return now > min ? now : min
} else {
return Reflect.get(target, key)
}
},
set(target, key, val) {
if (key === 'price') {
return Reflect.set(target, key, val)
}
return false
}
})
console.log(agent.phone) // 13988888888
console.log(agent.price) // 100000
agent.price = 100 * 2000
console.log(agent.price) // 200000
跟踪属性访问: Vue3 响应式实现原理
const user = {
name: '张三'
}
const proxy = new Proxy(user, {
get(...args) {
return Reflect.get(...args)
},
set(target, key, val) {
return Reflect.set(target, key, val)
}
})
proxy.name = '李四'
console.log(proxy.name) // '李四'
隐藏属性: 拒绝某些属性的访问和设置
// 隐藏Key
const hiddenProps = ['girlfriend']
const user = {
name: '张三',
girlfriend: '李红'
}
const proxy = new Proxy(user, {
get(target, key) {
if (hiddenProps.includes(key)) return undefined
return Reflect.get(target, key)
},
has(target, key) {
if (hiddenProps.includes(key)) return false
return Reflect.has(target, key)
}
})
console.log('girlfriend', proxy.girlfriend) // undefined
console.log('girlfriend' in proxy) // false
验证: 建议使用 TS
const user = {
name: '张三',
age: 25
}
const proxy = new Proxy(user, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, val) {
if (key === 'age') {
if (typeof val !== 'number') return false // 验证 age 类型
}
return Reflect.set(target, key, val)
}
})
proxy.age = '18'
console.log(proxy.age) // 25
记录实例
const userList = new WeakSet() // 记录表 ~ 每次初始化 user 进行记录
class User {
constructor(name) {
this.name = name
}
}
const ProxyUser = new Proxy(User, {
construct(...args) {
const user = Reflect.construct(...args)
userList.add(user) // 记录
return user
}
})
const user1 = new ProxyUser('张三')
const user2 = new ProxyUser('李四')
console.log(userList.has(user1)) // true
捕获器不变式: 代理无法改变对象本身原有的属性设置
const obj = { x: 100, y: 0 }
Object.defineProperty(obj, 'y', {
value: 200,
writable: false,
configurable: false,
})
const proxy = new Proxy(obj, {
get() {
return 'abc'
}
})
console.log(proxy.x)
console.log(proxy.y) // y 属性描述符被修改,proxy 不能修改它的值
this: 函数里的 this 是由执行时确认的,而非定义时。
const user = {
name: '张三',
getName() {
console.log('this...', this)
return this.name
}
}
const proxyUser = new Proxy(user, {})
user.getName() // this 是 user
proxyUser.getName() //this 是 proxy