vue 3.0前瞻之学习proxy

了解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)

原文地址:https://www.cnblogs.com/loveliang/p/13705165.html