浅谈Proxy

127 阅读4分钟

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可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。