个人学习之Proxy、Reflect使用(微深入)

Proxy

创建一个Proxy

const proxy = new Proxy(target, handler)

target:是要包装的对象,可以是任何东西,包括函数。
handler: 是代理配置:带有“捕捉器”或者“拦截器”的对象。比如 get 捕捉器用于读取 target 的属性,set 捕捉器用于写入 target 的属性,等等。

  • 设置简单的get拦截
const user= {name:'san'}
const userProxy = new Proxy(user,{
    get(target,prop){
        return target[prop]
    }
})    // userProxy.name: 'san'

在这里插入图片描述

  • 设置get的默认值和参数说明
const array = [1,2,3,4,5,6]
const arrayProxy = new Proxy(array,{
    get(target,prop){
        if(prop in target){
            return target[prop]
        }
        return '你的是个吨的代码'
    }
})
arrayProxy[5]      // 输出  6
arrayProxy[888]  // 输出    '你的是个吨的代码'

在这里插入图片描述

以上的get都用到了target和prop两个参数。但是get有三个参数,详解如下

  1. target: 是目标对象,该对象被作为第一个参数传递给 new Proxy。
  2. property: 目标属性名。
  3. receiver: 如果目标属性是一个 getter 访问器属性,则 receiver 就是本次读取属性所在的 this 对象。通常,这就是 proxy 对象本身(或者,如果我们从 proxy 继承,则是从该 proxy 继承的对象)。

下面是来自官方的建议(去看看

代理应该在所有地方都完全替代目标对象。目标对象被代理后,任何人都不应该再引用目标对象。否则很容易搞砸。
在这里插入图片描述

tips:所以我上面为了区分原始对象和代理对象的写法是不对的

tips:所以我上面为了区分原始对象和代理对象的写法是不对的

tips:所以我上面为了区分原始对象和代理对象的写法是不对的

  • 设置set拦截
let user = {}
user = new Proxy(user,{
    set(target, prop, val){
        if (prop) {
            console.log(prop)
            target[prop] = val
            return true
        }
        return false
    }
})

在这里插入图片描述
以上的set使用了set()的三个参数,set还有一个和get一样的receiver

  1. target: 是目标对象,该对象被作为第一个参数传递给 new Proxy,
  2. property: 目标属性名称,
  3. value: 目标属性的值,
  4. receiver: 与 get 捕捉器类似,仅与 setter 访问器属性相关。
  • Proxy的全部拦截器

以下的各个拦截器其内部方法和Object的方法作用一样,名称大致相同,handler方法为Proxy Handler方法 触发时机如下表和图所示:(object的函数解释:个人版传送官网版传送

内部方法Handler 方法何时触发
[[Get]]get读取属性
[[Set]]set写入属性
[[HasProperty]]hasin 操作符
[[Delete]]deletePropertydelete 操作符
[[Call]]apply函数调用
[[Construct]]constructnew 操作符
[[GetPrototypeOf]]getPrototypeOfObject.getPrototypeOf
[[SetPrototypeOf]]setPrototypeOfObject.setPrototypeOf
[[IsExtensible]]isExtensibleObject.isExtensible
[[PreventExtensions]]preventExtensionsObject.preventExtensions
[[DefineOwnProperty]]definePropertyObject.defineProperty, Object.defineProperties
[[GetOwnProperty]]getOwnPropertyDescriptorObject.getOwnPropertyDescriptor, for…in, Object.keys/values/entries
[[OwnPropertyKeys]]ownKeysObject.getOwnPropertyNames, Object.getOwnPropertySymbols, for…in, Object.keys/values/entries

在这里插入图片描述

Reflect

Reflect 是ES6之后的一个内建对象,可简化 Proxy 的创建。

前面所讲过的内部方法,例如 [[Get]] 和 [[Set]] 等,都只是规范性的,不能直接调用。
Reflect 对象使调用这些内部方法成为了可能。它的方法是内部方法的最小包装。

  • Reflect 调用的示例
操作Reflect 调用内部方法
obj[prop]Reflect.get(obj, prop)[[Get]]
obj[prop] = valueReflect.set(obj, prop, value)[[Set]]
delete obj[prop]Reflect.deleteProperty(obj, prop)[[Delete]]
new F(value)Reflect.construct(F, value)[[Construct]]
和get相同…和get相同…和get相同…

对于每个可被 Proxy 捕获的内部方法,在 Reflect 中都有一个对应的方法,其名称和参数与 Proxy 捕捉器相同。

  • ReFlect 基本用法
let user = {};

Reflect.set(user, 'name', 'John');

在这里插入图片描述

  • 用ReFlect重写一下前面的get、set
let user = {name: '张三'}
user = new Proxy(user,{
    get(target,prop,receiver){
        alert(prop)
        return Reflect.get(...arguments)
    },
    set(target, prop, val, receiver){
        alert(prop,val)
        return Reflect.set(...arguments)
    }
})

在这里插入图片描述

  • Proxy不是万能的有些对象不能直接代理

以下代码直接报错

let map = new Map()
map = new Proxy(map,{})
map.set('test',1) 
   //  Uncaught TypeError: Method Map.prototype.set called on incompatible receiver #<Map>
   // at Proxy.set (<anonymous>)
   // at <anonymous>:1:5

在这里插入图片描述

  • 解决方案
let map = new Map()
map = new Proxy(map,{
    get(target,prop,receiver){
        const value = Reflect.get(...arguments)
        return typeof value == 'function' ? value.bind(target) : value
    }
})
map.set('test',1)
map.get('test')    //   输出   1

在这里插入图片描述

总结

Proxy 是对象的包装器,将代理上的操作转发到对象,并可以选择捕获其中一些操作。它可以包装任何类型的对象,包括类和函数。
语法为:

let proxy = new Proxy(target, {
  /* trap */
});

·······然后,在任何地方都应该使用proxy而不是使用target。代理没有自己的属性或者方法,如果提供了捕捉器(trap),它将捕获操作,否则将直接转发给target对象。

  1. 读取(get),写入(set),删除(deleteProperty)属性(甚至是不存在的属性)。
  2. 函数调用(apply 捕捉器)。
  3. new 操作(construct 捕捉器)。
  4. 许多其他操作(可以参考文章上面的或者文档

Reflect API 旨在补充 Proxy。对于任意 Proxy 捕捉器,都有一个带有相同参数的 Reflect 调用。我们应该使用它们将调用转发给目标对象。

Proxy 有一些局限性:

  1. 内建对象具有“内部插槽”,对这些对象的访问无法被代理。(解决方案如上文)
  2. 私有类字段也是如此,因为它们也是在内部使用插槽实现的。因此,代理方法的调用必须具有目标对象作为 this 才能访问它们。
  3. 对象的严格相等性检查 === 无法被拦截。
  4. 性能:基准测试(benchmark)取决于引擎,但通常使用最简单的代理访问属性所需的时间也要长几倍。实际上,这仅对某些“瓶颈”对象来说才重要。

扩展

已知目前浅学了Proxy、ReFlect、Object对象、原形、以及VUE2的双向绑定简单实现是由Object.defineProperty拦截get,set等知识。尝试简单实现VUE3的双向绑定简单实现。


大写斜体加粗的GG


  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于"vue3proxy结合reflect"的问题,我理解你可能想了解如何在Vue 3中使用ProxyReflect结合起来。Vue 3是一个流行的JavaScript框架,而ProxyReflect则是ES6中新增的特性。 在Vue 3中,可以使用Proxy对象来代理Vue实例,以便捕获对数据的访问和修改。Proxy对象可以拦截并处理对Vue实例的操作,比如读取、设置和删除属性等。而Reflect对象提供了一组用于操作对象的方法,比如Reflect.get()、Reflect.set()和Reflect.deleteProperty()等。 结合使用ProxyReflect可以提供更灵活的控制和监控能力。你可以通过在Vue实例上创建一个代理对象,来拦截对数据的访问和修改,并在代理处理器中使用Reflect方法来操作实际的数据。这样可以轻松地实现对数据的拦截、校验、代理等功能。 下面是一个简单的示例代码,展示了如何在Vue 3中使用ProxyReflect结合起来: ```javascript const data = { message: 'Hello, Vue!', }; const proxy = new Proxy(data, { get(target, key) { console.log('Getting ' + key); return Reflect.get(target, key); }, set(target, key, value) { console.log('Setting ' + key + ' to ' + value); return Reflect.set(target, key, value); }, }); // 创建Vue应用 const app = Vue.createApp({ data() { return proxy; // 使用代理对象 }, }); app.mount('#app'); ``` 在上面的代码中,我们创建了一个名为data的普通对象,并使用Proxy对象创建了一个代理对象proxy。在代理对象的get和set处理器中,我们分别使用Reflect.get和Reflect.set来操作实际的数据。这样,当我们通过Vue实例访问或修改数据时,会触发代理处理器,并通过Reflect方法操作实际的数据。 希望这个例子能帮助到你,如果还有其他问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值