持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情
监听对象的操作
在javascript中,如果我们想要监听某个对象中的属性被设置或者获取的过程,应该如何去做呢?
答案是利用Object对象上defineProperty方法。
let obj={
name:"jojo",
age:12
}
Object.keys(obj).forEach(key=>{
let value = obj[key]
Object.defineProperty(obj,key,{
set:function(newValue){
console.log('key改变了值: ', newValue);
},
get:function(){
console.log('监听获取obj对象的值: ');
return value
}
})
})
console.log(obj.name)
obj.name="gogo"
结果打印如下,可以知道已经对obj对象实现了监听
但是如果我们想要监听更多的操作,比如新增属性、删除属性,那么这个方法就做不到了,因此这里引入了另一个对象Proxy用来做更多的操作。
Proxy使用
这是ES6之后新增的一个代理对象,可以监听一个对象的相关操作。
普通对象代理
set和get分别对应的是函数类型;
set函数有四个参数:
target:目标对象(侦听的对象);
property:将被设置的属性key;
value:新属性值;
receiver:调用的代理对象;
get函数有三个参数:
target:目标对象(侦听的对象);
property:被获取的属性key;
receiver:调用的代理对象;
这里要注意的是如果监听对象有setter、getter访问器属性,那么可以通过receiver来改变里面的this。
let obj={
name:"jojo",
age:12
}
const objProxy = new Proxy(obj,{
has:function(target,key) {
console.log('是否拥有key: ', key);
return key in target
},
set:function(target,key,value) {
console.log('设置key的值: ', key,value);
target[key] = value
},
get:function(target,key) {
console.log('获取某个key的值: ', key);
return target[key]
},
deleteProperty:function(target,key) {
console.log('删除了某个key: ', key);
delete target[key]
},
})
console.log(objProxy.name)
objProxy['weight']=230
objProxy.name="gogo"
对某个对象设置了Proxy后,之后直接使用代理对象进行操作即可,就能监听到各类操作了。
函数对象代理
主要是针对函数,可以做一个代理,监听到调用的操作。
function foo(){
console.log('foo函数调用了: ', this,arguments);
}
const fooProxy = new Proxy(foo,{
apply:function(target,thisArg,otherArgs){
console.log('函数apply: ');
return target.apply(thisArg,otherArgs)
},
construct(target, argArray, newTarget) {
console.log(target,argArray,newTarget);
return new target()
},
})
fooProxy()
fooProxy.apply(obj)
Reflect使用
这可以理解为一个反射对象,提供了很多操作JS对象的方法。
常用方法有如下,和Proxy也是一一对应的
- Reflect.getPrototypeOf(target)
类似于 Object.getPrototypeOf()。
- Reflect.setPrototypeOf(target, prototype)
设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回
true。
- Reflect.isExtensible(target)
类似于 Object.isExtensible()
- Reflect.preventExtensions(target)
类似于 Object.preventExtensions()。返回一个Boolean。
- Reflect.getOwnPropertyDescriptor(target, propertyKey)
类似于 Object.getOwnPropertyDescriptor()。如果对象中存在
该属性,则返回对应的属性描述符, 否则返回 undefined.
- Reflect.defineProperty(target, propertyKey, attributes)
和 Object.defineProperty() 类似。如果设置成功就会返回 true
- Reflect.ownKeys(target)
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于
Object.keys(), 但不会受enumerable影响).
- ** Reflect.has(target, propertyKey)**
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
- Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于 target[name]。
- ** Reflect.set(target, propertyKey, value[, receiver])**
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
- Reflect.deleteProperty(target, propertyKey)
作为函数的delete操作符,相当于执行 delete target[name]。
- Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和
Function.prototype.apply() 功能类似。
- Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行 new 操作,相当于执行 new target(...args)。
前面Proxy的写法可以利用Reflect改造成下面
const objProxy = new Proxy(obj,{
has:function(target,key) {
console.log('是否拥有key: ', key);
return Reflect.has(target,key)
},
set:function(target,key,value) {
console.log('设置key的值: ', key,value);
return Reflect.set(target,key,value)
},
get:function(target,key) {
console.log('获取某个key的值: ', key);
return Reflect.get(target,key)
},
deleteProperty:function(target,key) {
console.log('删除了某个key: ', key);
return Reflect.deleteProperty(target,key)
},
})
总结
Proxy与Reflect对象还是比较重要的,也是vue3响应式原理的一部分,是需要掌握的一个技术点。