Proxy浅解
详解参照 MDN-Proxy
Proxy定义
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
语法
const p = new Proxy(target, handler)
参数
target
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler 一个通常以函数作为属性的对象,各属性中的函数分别定了在执行各种操作时代理P的行为。
handler对象的方法
handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
Proxy常用的13种拦截(捕捉器)操作
get(target, propKey, receiver)//拦截对象属性的读取,比如proxy.foo和proxy['foo']。
set(target, propKey, value, receiver)//拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
has(target, propKey)//拦截propKey in proxy的操作,返回一个布尔值。
deleteProperty(target, propKey)//拦截delete proxy[propKey]的操作,返回一个布尔值。
ownKeys(target)
//拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,
//返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor(target, propKey)//拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc)
//拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions(target)//拦截Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf(target)//拦截Object.getPrototypeOf(proxy),返回一个对象。
isExtensible(target)//拦截Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf(target, proto)
//拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args)
//拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
construct(target, args)//拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
拦截操作详细介绍
handler.get()
描述:handler.get 方法用于拦截对象的读取属性操作
语法
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
参数:
target: 目标对象
property: 属性名
receiver:Proxy或者继承Proxy的对象
举例:
//例1 当访问对象的属性不存在时,返回‘不存在该属性’,否则返回相应的属性值
let person = {
name:'张三',
age:'19'
}
let proxy = new Proxy(person,{
get:function(target, propKey){
if(propKey in target){
return target[propKey]
}else{
return '不存在该属性'
}
}
})
console.log('proxy', proxy)//{name:'张三', age: 19}
console.log('属性name', proxy.name) //张三
console.log('属性age', proxy.gender) //
//例2 讲对象xiaowang的loveLetter属性值修改为晨辉沐浴
let xiaowang = {
loveLetter:'睡觉'
}
let proxy2 = new Proxy(xiaowang,{
get(target,key){
if(key === 'loveLetter'){
return target[key] = '晨辉沐浴'
}
}
})
console.log(proxy2.loveLetter)//晨辉沐浴
handler.set()
语法
let p = new Proxy(target,{
set:function(target, property, value, receiver){
}
})
参数:
target: 目标对象
property: 属性名
value: 新属性值
receiver:Proxy或者继承Proxy的对象
返回值:
set()方法返回布尔值 true则表示赋值成功
例1 //大于100转换为100 小于0转换为0
const number = [];
const proxyNum = new Proxy(number,{
set:function(target,key,value,receiver){
if(value >100){
value = 100
}else if(value <0){
value = 0
}
target[key] = value
return true;
}
})
proxyNum.push(1000) //100
proxyNum.push(-100) //0
proxyNum.push(50)//50
console.log('proxyNum', proxyNum);// [100,0,50]
例2 每次新增属性时都打印 新增属性及属性值
const objPerson = {
name:'印度阿三'
}
let proxySet = new Proxy(objPerson,{
set(target, key, value){
if(!target.hasOwnProperty(key)){
console.log(`新增属性${key},属性值是${value}`)
}
target[key] = value
return true;
}
})
proxySet.xfln = '君王'
//打印:新增属性xcq,属性值是君王
handler.has()
handler.has() 方法是针对 in 操作符的代理方法
语法
var p = new Proxy(target, {
has: function(target, prop) {
}
});
参数:
target: 目标对象
prop:需要检查是否存在的属性
返回值:
set()方法返回布尔值 true则表示赋值成功
例子1、私有属性不对外暴露
let handler = {
has:function(target, key){
if(key[0] === '_'){
return false;
}else{
return key in target
}
}
}
const monster1 = {
_secret: 'easily scared',
eyeCount: 4
};
let proxyHas = new Proxy(monster1,handler)
console.log('_secret' in proxyHas)//false
console.log('eyeCount' in proxyHas)//true
console.log('_secret' in monster1)//true
总结
Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。