Proxy这个单词,翻译过来,就是代理,是 ES6 中提供的新 API
Proxy对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)
(在文档中被称为 traps(陷阱),我觉得可以理解为针对对象各种行为的钩子)
const p = new Proxy(target, handler)
target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
let target = {}
let handlers = {} // do nothing
let proxy = new Proxy(target, handlers)
proxy.a = 123
console.log(target.a) // 123
在第二个参数为空对象的情况下,基本可以理解为是对第一个参数做的一次浅拷贝(Proxy必须是浅拷贝,如果是深拷贝则会失去了代理的意义)
getter、setter属性let obj = {
_age: 20,
get age() {
return `I'm ${this._age} years old`
},
set age(val) {
this._age = Number(val)
}
}
console.log(obj.age) // I'm 20 years old
obj.age = 21
console.log(obj.age) // I'm 21 years old
就像这段代码描述的一样,我们设置了一个属性 _age,然后又设置了一个 get age 和 set age
然后我们可以直接调用 obj.age 来获取一个返回值,也可以对其进行赋值。
这么做有几个缺点:
getter、setterkey(如果我们直接在getter里边调用this.age则会出现堆栈溢出的情况,因为无论何时调用this.age进行取值都会触发getter)。
Proxy很好的解决了这两个问题:let obj = {
name: ‘hk’,
age: 20
}
let handlers = {
get(target, property) {
if (property === ‘name') {
return `My name is ${target[property]}`
} else if (property === ‘age’) {
return `I am ${target[property]} years old`
}
return target[property]
}
set (target, property, value) {
target[property] = value
}
}
let proxy = new Proxy(obj, handlers)
console.log(proxy.name, obj.name) // My name is hk hk
console.log(proxy.age, obj.age) // I'm 20 years old 20
obj.age = 21
console.log(obj.age) // 21
我们通过创建get、set两个trap来统一管理所有的操作,可以看到,在修改proxy的同时,obj的内容也被修改,而且我们对proxy的行为进行了一些特殊的处理。
而且我们无需额外的用一个key来存储真实的值,因为我们在trap内部操作的是target对象,而不是proxy对象
确定一个对象是否是一个代理是不可能的 根据Javascript语言规范,无法确定对象是否是代理。 但是,在 Node 10+上,可以使用 util.types.isProxy 方法。