学习ES6(六):代理Proxy

10 篇文章 0 订阅

proxy概述

为了更好地去理解proxy代理,在此之前举个例子来解释一下何为代理。
首先,从字面意思上我们更容易明白,代理就是把需要你做的事交给另一方去代替你完成。比如我需要去交一份文件到某个地方,我又没有空,那么我可以找一个跑腿去帮我交,这就是一个代理的过程,把本属于我要做的交给另一个人帮我完成。
是不是很好理解呢?
那么在ES6中,这个代理又起什么作用呢?让我们引出下面的内容

一、Proxy的结构

let obj = new Proxy(
        {//代理对象},
        {
        //这里是拦截处理函数
            get:function(target,propkey,receiver){},
            set:function(target,propkey,value,receiver){}
        }
    )
  • 它是通过new关键字来创建的。并且是按照 new Proxy(target,handler)的形式来的。
  • target是指 代理的对象。
  • handler是指 一系列的函数,对象类型。这里的函数都是针对与代理对象有关的操作来触发。
  • handler称为定制的拦截行为,如果这里的handler为空对象的话,那意思就是该对象没有任何代理拦截,默认就会直接通向原对象。

二、基本使用

1.将proxy设置到对象上。

针对绑定到对象上的proxy属性,我们可以设置通过将new Proxy绑定到对象的属性上面。然后我们通过访问对象该属性来触发该对象的proxy handler。

let obj = {
        proxy: new Proxy(this,{
            get(target,prop){
                console.log(`getting ${prop}`)
                return target[prop]??"Not Found"
            }
        })
    }
    let x = obj.proxy.a;
    console.log(x)
//输出:getting a --->这里是console.log(`getting ${prop}`)的执行结果
//Not Found --->这里是console.log(x)的执行结果。

释义:这里我们声明obj对象,并且设置了proxy属性值为一个拦截器,拦截器有两个参数,第一个参数我们传入的是this,因为我们要将拦截器绑定到obj上,所以这里的this指代的是当前的上下文对象,也就是obj。然后这里的handler对象有一个get函数处理针对获取obj某个属性值的操作。(具体有哪些handler处理函数会在最后给出) 我们在get处理函数中,将要取出的属性打印出来,如果存在该属性就返回该属性对应的属性值,否则返回“Not Found”。因为obj没有a属性,所以我们通过obj.proxy来访问a的时候会得到相应输出。

这里我们必须要通过obj.proxy来访问属性,因为proxy执行是需要执行上下文的,如果直接通过obj.a来访问的话,是没有执行new proxy来绑定代理对象的,肯定会返回undefined的,因为当前obj是没有a属性的。

2.基本的拦截handler操作(get,set,apply)

同一个拦截器对象,可以设置多个操作。这里只列举一部分

1.get操作:用于拦截属性的读取操作。有三个参数,分别为目标对象、属性名和proxy本身,一般都用前两个。

let proxy = new Proxy(
        {},
        {
            get(target,propkey){
                return 35
            }
        }
    )
console.log(proxy.time) //输出35
console.log(proxy.name) //输出35
console.log(proxy.title) //输出35

我们设置将代理对象设置为空,handler设置一个拦截属性读取的操作。
只要访问proxy的属性,那么就返回35。
如果handler和代理对象都为空,那么就直接对代理对象进行操作。如下所示

let target = {} //定义代理对象
let handler = {} //定义handler操作
let p = new Proxy(target,handler)
p.a = "b" //设置属性
console.log(target,p.a) //输出:{a:"b"}  b 
target.a = "bb"
console.log(target,p.a) //输出:{a:"bb"}  bb

因为这里的handler为空。那么我们可以通过实例化对象来直接修改代理对象的属性。
所以当我们在设置p的属性时,他会去修改proxy对象绑定的对象target。所以target就有了属性a,并且属性值为b,这时候既然target本身有了属性a,那么肯定可以对a进行其他操作了。

2.set操作:用于拦截属性的设置操作。有四个参数,分别为目标对象、属性名、属性值和proxy本身,一般都用前两个。
和get操作类似,get操作是我们拦截读取操作,而set操作是我们拦截设置操作。代码如下:

let target = { a:'1'}
let handler = {
        set:function(target,propkey){
            console.log("你想设置:",propkey)
            return "设置失败"
        }
}
let p = new Proxy(target,handler)
p.a = "2"
console.log(target,p.a)
//输入:你想设置: a ---> console.log("你想设置:",propkey)
//{ a: '1' } 1 ---> console.log(target,p.a)

这里对象target已经有了属性a,并且值为1,如果我们不想要别人来修改该属性的时候,我们可以通过拦截set操作来禁止别人进行修改。

3.apply操作:用于拦截属性的调用、call和apply操作。有三个参数,分别为目标对象、目标对象的上下文this和目标对象的参数数组。

let handler = {
    apply(target,thisBinding,args){
            return args[0]
   },
}
let fproxy = new Proxy(
        function(x,y){
            return x+y
        },
        handler
)
console.log(fproxy(1,2))// 输出为 1

如果代理对象没有拦截针对apply的操作的话,返回值为 1+2的和。我们在调用fproxy(1,2)函数的时候,会去先去寻找代理中针对函数调用的拦截,所以会返回参数数组的第一个元素。

针对handler操作的补充

  1. get(target,propkey,receiver):拦截对象属性的读取。
  2. set(target,prokey,value,receiver):拦截对象属性的设置。
  3. has(target,propkey):拦截 propkey in proxy 的操作。
  4. deleteProperty(target,propkey):拦截 delete proxy[propkey] 的操作。
  5. ownKeys(target):拦截 Object.getOwnPropertyNames(proxy) 、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环
  6. getOwnPropertyDescriptor(target,propkey):拦截Object.getOwnPropertyDescriptor(proxy,propkey)。
  7. defineProperty(target,propkey,propDesc):拦截Object.defineProperty(proxy,propkey,propDesc)、Object.defineProperties(proxy,propDescs)。
  8. preventExtensions(target):拦截Object.preventExtensions(proxy)
  9. getPrototypeOf(target):拦截Object.getPrototypeOf(proxy)
  10. isExtensible(target):拦截Object.isExtensible(proxy)。 、
  11. setPrototypeOf(target,proto):拦截Object.setPrototypeOf(proxy,proto)
  12. apply(target,object,args):拦截 Proxy 实例作为函数调用的操作。比如proxy(…args)、proxy.call(object,…args)、proxy.apply(…)。
  13. construct(target,args):拦截 Proxy 实例作为构造函数调用的操作,比如proxy(…args)。

参考资料
https://es6.ruanyifeng.com/#docs/proxy ES6标准入门(第三版)
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy MDN Proxy文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值