需求:有一个对象,我们希望监听这个对象中的属性被设置或获取的过程
这段代码就利用了 Object.defineProperty 的存储属性描述符来对属性的操作进行监听
const obj = {
name: 'why',
age: 18
}
Object.keys(obj).forEach((key) => {
let value = obj[key]
Object.defineProperty(obj, key, {
get: function () {
console.log(`监听到obj对象的${
key}属性被访问了`)
return value
},
set: function (newValue) {
console.log(`监听到obj对象的${
key}属性被设置值`)
value = newValue
}
})
})
obj.name = 'kobe'
obj.age = 30
console.log(obj.name)
console.log(obj.age)
/*
监听到obj对象的name属性被设置值
监听到obj对象的age属性被设置值
监听到obj对象的name属性被访问了
kobe
监听到obj对象的age属性被访问了
30
*/
属性描述符监听对象的缺点:
Object.defineProperty 设计的初衷,不是为了去监听截止一个对象中所有的属性的
Object.defineProperty 是无能为力的Object.defineProperty 变成了 访问属性描述符在ES6中,新增了一个Proxy类,这个类从名字就可以看出来,是用于帮助我们创建一个代理的:
将上面的案例用 Proxy 来实现一次:
new Proxy 对象,并且传入需要侦听的对象以及一个处理对象,可以称之为 handler;const p = new Proxy(target, handler)
其次,我们之后的操作都是直接对 Proxy 的操作,而不是原有的对象,因为我们需要在 handler 里面进行侦听
const obj = {
name: 'why',
age: 18
}
const objProxy = new Proxy(obj, {
// 获取值时的捕获器
get: function (target, key) {
console.log(`监听到obj对象的${
key}属性被访问了`)
return target[key]
},
// 设置值时的捕获器
set: function (target, key, newValue) {
console.log(`监听到obj对象的${
key}属性被设置值`)
target[key] = newValue
}
})
console.log(objProxy.name)
console.log(objProxy.age)
objProxy.name = 'kobe'
objProxy.age = 30
console.log(obj.name)
console.log(obj.age)
/*
监听到obj对象的name属性被访问了
why
监听到obj对象的age属性被访问了
18
监听到obj对象的name属性被设置值
监听到obj对象的age属性被设置值
kobe
30
*/
handler 中添加对应的捕捉器(Trap)set 和 get 分别对应的是函数类型
set 函数有四个参数:
target:目标对象(侦听的对象)property:将被设置的属性 keyvalue:新属性值receiver:调用的代理对象get 函数有三个参数
target:目标对象(侦听的对象)property:被获取的属性 keyreceiver:调用的代理对象handler.getPrototypeOf()
Object.getPrototypeOf 方法的捕捉器handler.setPrototypeOf()
Object.setPrototypeOf 方法的捕捉器handler.isExtensible()
Object.isExtensible 方法的捕捉器handler.preventExtensions()
Object.preventExtensions 方法的捕捉器handler.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor 方法的捕捉器handler.defineProperty()
Object.defineProperty 方法的捕捉器handler.ownKeys()
Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器handler.has()
in 操作符的捕捉器handler.get()
handler.set()
handler.deleteProperty()
delete 操作符的捕捉器handler.apply()
handler.construct()
new 操作符的捕捉器const obj = {
name: 'why',
age: 18
}
const objProxy = new Proxy(obj, {
// 获取值时的捕获器
get: function (target, key) {
console.log(`监听到obj对象的${
key}属性被访问了`)
return target[key]
},
// 设置值时的捕获器
set: function (target, key, newValue) {
console.log(`监听到obj对象的${
key}属性被设置值`)
target[key] = newValue
},
// 监听 in 的捕获器
has: function (target, key) {
console.log(`监听到obj对象的${
key}属性的in操作`)
return key in target
},
// 监听 delete 的捕获器
deleteProperty: function (target, key) {
console.log(`监听到obj对象的${
key}属性的delete操作`)
delete target[key]
}
})
// in 操作符
console.log('name' in objProxy)
// delete 操作
delete objProxy.name
/*
监听到obj对象的name属性的in操作
true
监听到obj对象的name属性的delete操作
*/
construct 和 apply,它们是应用于函数对象的function foo() {
console.log('调用了 foo')
}
const fooProxy = new Proxy(foo, {
apply: function (target, thisArg, argArray) {
console.log(`对 foo 函数进行了 apply 调用`)
target.apply(thisArg