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