当前位置 博文首页 > 文章内容

    vue 3.0前瞻之学习proxy

    作者: 栏目:未分类 时间:2020-09-21 14:00:25

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    了解proxy

    Proxy是ES6新推出的一个特性,可以用它去拦截js操作的方法,从而对这些方法进行代理操作。
    举个例子:

    const laowang = {
      loveLetter: '我喜欢你,我想和你睡觉'
    }
    const proxy = new Proxy(laowang, {
      get(target,key) {
        if(key === 'loveLetter') {
          return target[key].replace('睡觉','一起在晨辉的沐浴下起床')
        }
      }
    })
    // 送给小姐姐情书
    function sendToMyLove(obj) {
        console.log(obj.loveLetter)
        return '小伙子还挺有诗情画意的么,不过老娘不喜欢,滚'
    }
    console.log(sendToMyLove(proxy))
    
    

    初识Proxy

    Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。
    Proxy的语法格式如下:

    /**
    * target: 要兼容的对象,可以是一个对象,数组,函数等等
    * handler: 是一个对象,里面包含了可以监听这个对象的行为函数,比如上面例子里面的`get`与`set`
    * 同时会返回一个新的对象proxy, 为了能够触发handler里面的函数,必须要使用返回值去进行其他操作,比如修改值
    */
    const proxy = new Proxy(target, handler)
    
    

    handler 里面的方法列表
    1.handler.get:
    当通过proxy去读取对象里面的属性的时候,会进入到get钩子函数里面.
    2.handler.set
    当通过proxy去为对象设置修改属性的时候,会进入到set钩子函数里面.
    3.handler.has
    当使用in判断属性是否在proxy代理对象里面时,会触发has.
    4.handler.deleteProperty
    当使用delete去删除对象里面的属性的时候,会进入deleteProperty`钩子函数.
    5.handler.apply
    6.handle.ownKeys
    7.handler.construct
    8.handler.defineProperty
    9.handler.getPrototypeOf
    10.handler.setPrototypeOf
    11.handler.isExtensible
    12.handler.preventExtensions
    13.handler.getOwnPropertyDescriptor
    Proxy提供了十三种拦截对象操作的方法,建议可以直接阅读MDN关于Proxy的介绍。

    详细介绍

    get:当通过proxy去读取对象里面的属性的时候,会进入到get钩子函数里面
    当我们从一个proxy代理上面读取属性的时候,就会触发get钩子函数,get函数的结构如下

    /**
     * target: 目标对象,即通过proxy代理的对象
     * key: 要访问的属性名称
     * receiver: receiver相当于是我们要读取的属性的this,一般情况
     *           下他就是proxy对象本身,关于receiver的作用,后文将具体讲解
     */
    handle.get(target,key, receiver)
    
    

    举个例子
    我们在工作中经常会有封装axios的需求,在封装过程中,也需要对请求异常进行封装,比如不同
    的状态码返回的异常信息是不同的,如下是一部分状态码及其提示信息:

    // 状态码提示信息
    const errorMessage = {
      400: '错误请求',
      401: '系统未授权,请重新登录',
      403: '拒绝访问',
      404: '请求失败,未找到该资源'
    }
    
    // 使用方式
    const code = 404
    const message = errorMessage[code]
    console.log(message)
    

    但这存在一个问题,状态码很多,我们不可能每一个状态码都去枚举出来,所以对于一些异常状态码,
    我们希望可以进行统一提示,如提示为系统异常,请联系管理员,这时候就可以使用Proxy对错误信息进行代理处理

    // 状态码提示信息
    const errorMessage = {
      400: '错误请求',
      401: '系统未授权,请重新登录',
      403: '拒绝访问',
      404: '请求失败,未找到该资源'
    }
    
    const proxy = new Proxy(errorMessage, {
      get(target,key) {
        const value = target[key]
        return value || '系统异常,请联系管理员'
      }
    })
    
    // 输出 错误请求
    console.log(proxy[400])
    // 输出 系统异常,请联系管理员
    console.log(proxy[500])
    

    set:当为对象里面的属性赋值的时候,会触发set
    set函数的结构如下:

    /**
     * target: 目标对象,即通过proxy代理的对象
     * key: 要赋值的属性名称
     * value: 目标属性要赋的新值
     * receiver: 与 get的receiver 基本一致
     */
    handle.set(target,key,value, receiver)
    

    举个例子
    某系统需要录入一系列数值用于数据统计,但是在录入数值的时候,可能录入的存在一部分异常值,对于这些异常值需要在录入的时候
    进行处理, 比如大于100的值,转换为100, 小于0的值,转换为0, 这时候就可以使用proxy的set,在赋值的时候,对数据进行处理

    const numbers = []
    const proxy = new Proxy(numbers, {
      set(target,key,value) {
        if(value < 0) {
          value = 0
        }else if(value > 100) {
          value = 100
        }
        target[key] = value
        // 对于set 来说,如果操作成功必须返回true, 否则会被视为失败
        return true
      }
    })
    
    proxy.push(1)
    proxy.push(101)
    proxy.push(-10)
    // 输出 [1, 100, 0]
    console.log(numbers)
    

    对比Vue2.0
    使用Vue2.0的时候,如果给对象添加新属性的时候,往往需要调用$set, 这是因为Object.defineProperty只能监听已存在的属性

    而新增的属性无法监听,而通过$set相当于手动给对象新增了属性,然后再触发数据响应。但是对于Vue3.0来说,因为使用了Proxy,

    在他的set钩子函数中是可以监听到新增属性的,所以就不再需要使用$set。

    has:当使用in判断属性是否在proxy代理对象里面时,会触发has

    /**
     * target: 目标对象,即通过proxy代理的对象
     * key: 要判断的key是否在target中
     */
     handle.has(target,key)
    

    deleteProperty:当使用delete去删除对象里面的属性的时候,会进入deleteProperty拦截器

    /**
     * target: 目标对象,即通过proxy代理的对象
     * key: 要删除的属性
     */
     handle.deleteProperty(target,key)