概念
- 为其他对象提供一种代理以控制对这个对象的访问
- 直接访问会给使用者或者系统结构带来很多麻烦,在访问此对象时加上一层访问层
- 装饰器模式不能改变原始对象的行为
- 代理模式可以改变原始对象的行为(代理和目标都可自行扩展)
- DOM 事件代理( 也叫事件委托 )
const container= document.getElementById('container')
container.addEventListener('click', function (e) {
const target = e.target
if (target.nodeName === 'A') {
// ... do something
}
})
- 正向代理:webpack-dev-server ~ proxy
- nginx 反向代理,客户端只需要根据服务端给定端口进行访问
理解
你通过房产中介买房子,中介就是一个代理
// 户主
class master {
sign() {
console.log('户主签字')
}
}
// 代理
class agent {
constructor() {
this.master = new master()
}
// 签约
sign() {
// ... 按指纹、交定金、顾客签字等限制
this.master.sign() // 和户主签约
}
}
const proxy = new agent()
proxy.sign()
Proxy、Reflect
Proxy
用来创建一个对象的代理,可以实现数据的拦截和自定义Reflect
不是一个构造器,不能通过 new 操作符实例,用于代理对象操作get
:读取、set
:设置、deleteProperty
:删除、ownKeys
:遍历
let user = {}
user = new Proxy(user, {
get(target, key) {},
set(target, key, val) {},
deleteProperty(target, key) {},
ownKeys(target) {}
})
明星和经纪人,主办方需要联系经纪人进行签约和报价,而非联系明星。
// 明星
const star = {
name: '张国荣',
age: '18',
address: '****', // 地址
salary: '****', // 薪水
phone: '****', // 号码
price: 0 // 出场费
}
const min = 1000 * 1000 // 最少出场费
const agentTel = '139 **** 8888' // 经纪人电话
const privaInfo = ['salary', 'address'] // 私密信息不公开
// 经纪人
const agent = new Proxy(star, {
get(target, key) {
if (key === 'phone') {
// 经纪人电话
return agentTel
} else if (privaInfo.includes(key)) {
// 私密信息
return undefined
} else {
return Reflect.get(target, key)
}
},
set(target, key, val) {
if (key === 'price' && typeof val === 'number') {
// 出场费由积极人决定
const newVal = val > min ? val : min
return Reflect.set(target, key, newVal)
}
return false
}
})
console.log(agent.phone) // '139 **** 8888' 经纪人电话
console.log(agent.price) // 100000 // 经纪人报价
console.log(agent.age) // 18 公开属性
console.log(agent.address) // undefined
console.log(agent.salary) // undefined
agent.price = 1000 * 1000 * 5
console.log(agent.price) // 5000000 // 经纪人修改后的报价
记录实例
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('张三')
Notice
- 捕获器不变式: 代理无法改变对象本身原有的属性设置
const obj = { y: 0 }
Object.defineProperty(obj, 'y', {
value: 200,
writable: false, // 不可更改
configurable: false, // 不可配置
})
const proxy = new Proxy(obj, {
get() {
return 'abc'
}
})
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