Js中Proxy与Reflect的使用

159 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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对象实现了监听

image.png

但是如果我们想要监听更多的操作,比如新增属性、删除属性,那么这个方法就做不到了,因此这里引入了另一个对象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"

image.png

对某个对象设置了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)

image.png

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响应式原理的一部分,是需要掌握的一个技术点。