ES6中的Proxy代理拦截对象和Reflect对象

Proxy

在教程中对于Proxy的定义是这样的,Proxy用于修改某些操作的默认行为,即对编程语言层面进行修改,属于“元编程”,Proxy意思为“代理”,即在访问对象之前建立一道“拦截”,任何访问该对象的操作之前都会通过这道“拦截”,即执行Proxy里面定义的方法。

(1)ES6原生规定的Proxy的基本用法为

 let pro = new Proxy(target,handler);

其中 new Proxy相当于创建了一个Proxy实例,target为所要拦截的目标对象,handler也是一个对象,里面定义的是对拦截对象所要进行的拦截方法。

Proxy实例1

let target = {
    name:"小明",
    age: 15
}

let handler = {
    get:(target,name,)=>{
        return "success"
    }
}

let pro = new Proxy(target,handler);
console.log(pro.name); // success;

解释:创建的target对象为所要拦截的对象,handler对象为拦截对象后执行的操作,这里get方法为读取操作,即用户想要读取pro中的属性时执行的拦截操作。最后创建一个Proxy实例,因为我设定的读取拦截操作为返回一个“success”字符串,所以当我想读取pro中的属性时,结果打印出来的总是“success”字符串。

Proxy实例2

let target = {
    name:"小明",
    age:15
};

let handler = {};
let pro = new Proxy(target,handler);
console.log(pro.name);  //小明

pro.name = "小红";
console.log(pro.name); // 小红

解释:拦截操作对象handler为空,未对拦截对象设定拦截方法,该情况下pro直接指向原对象target,访问pro等同于访问target,所以结果为target中的结果。

Proxy实例3

Proxy也可以作为其他对象的原型对象使用

let target = {
    name:"小明",
    age:15
}

let handler = {
    get:(target,name){
        return "success";
    }
}

let pro = new Proxy(target,handler);
let obj = Object.create(pro);
console.log(obj.name);    // success

解释:上述实例将pro作为obj的原型对象使用,虽然obj本身没有name这个属性,但是根据原型链,会在pro上读取到name属性,之后会执行相对应的拦截操作。

(2)Proxy常用的拦截方法

1、get(target,name,property)方法,用于拦截某个读取属性的操作,第一个参数为目标对象,第二个参数为属性名称,第三个属性为操作所针对的对象(可选参数)。

let handler = {
    get:function(target,name,property){
        if(name in target){
            cosnole.log("success");
        }else{
            console.log("error")
        }
        return Reflect.get(target,name,property);
    }
}

let target = {
    name:"小明",
    age:15
}

let pro = new Proxy(target,handler);
pro.name;    //结果为 success
pro.grade;    //结果为error

2、set(target,name,value,property),用于拦截某个属性的赋值操作,第一个参数为目标对象,第二个参数为属性名,第三个参数为属性值,第四个参数为操作行为所针对的对象(可选参数)。

let handler = {
    set:function(target,name,value,property){
        if(typeof value != "number"){
            console.log("error");
            throw new TypeError('The age is not an integer');
        }else{
            console.log("success");
            return Reflect.set(target,name,value,property);
       }
   }    
}

let target = {
    name:"小明",
    age:15
}

let pro = new Proxy(target,handler);
pro.age = 35;    //结果为 success,并且返回修改值
pro.age = "12";    //结果为error,抛出错误
3、has(target,key),用来拦截对象是否具有某个属性值的操作,第一个参数为目标对象,第二个参数为属性名
let handler = {
    has:function(target,key){
        if(key[0] != "_"){
            return false
        }
        return true;
    }
}

let target = {
    _name:"小明",
    age:15
}

let pro = new Proxy(target,handler);
console.log("_name" in pro);    //打印结果为 true
console.log("age" in pro);    //打印结果为false

Reflect对象

概述

1、Reflect对象与Proxy对象一样,都是ES6对操作对象设计的API
2、对于我个人的理解而言,Reflect设计的目的是为了优化Object的一些操作方法以及合理的返回Object操作返回的结果,对于一些命令式的Object行为,Reflect对象可以将其变为函数式的行为

实例1

//旧写法
try{
    Object.defineProperty(target,name,property);
}catch(e){
    console.log("error");
}


//Reflect对象操作
if(Reflect(target,name,property)){
    console.log("success");
}else{
    console.log("error")
}

实例2  Reflect.has() 判断

let obj = {
    name:"小明",
    age:15
}

//旧写法   
console.log(name in obj);    //结果为 true

//Reflect对象操作
console.log(Reflect.has(obj,"name"));    //结果为 true

实例3
因为Reflect对象的操作和Proxy对象的操作是一一对应的,所以在Proxy的拦截操作中,可以直接利用Reflect对象直接获取Proxy的默认值

let target = {
    name:"小明",
    age:15
}

let handler = {
    get:function(target,name,property){
        if(name === "name"){
            console.log("success");
        }else{
            console.log("success");
        }
        return Reflect.get(target,name,property);
    }
}

let pro = new Proxy(target,handler);
console.log(pro.name)

//结果为
// success
//小明

 实例:使用Proxy实现观察者模式

观察者模式(Observer mode)指的是函数自动观察数据对象,一旦数据有变化,函数就会自动执行


//初始化观察者队列
const arr = new Set();

//将监听函数加入队列
const obe = fun => {
    arr.add(fun);
}

//初始化Proxy对象,设置拦截操作
const observable = obj => new Proxy(obj, {set});

function set(target, key, value, receiver){
    //内部调用对应的 Reflect 方法
    const result = Reflect.set(target, key, value, receiver);
    //额外执行观察者队列
    arr.forEach( item => item() );
    return Reflect.set(target, key, value, receiver);
}

const target = {
    name:"小明",
    age:15
}

const per = observable(target)
function print(){
    console.log( per.name);
}

obe(print);
per.name = "小红"

Reflect的静态方法

Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

Reflect对象的静态方法和Proxy对象的静态方法一一对应,所以在功能上也相同,不一一列举了
如果要查阅对应方法的用法实例,参照阮一峰老师的ES6语法ES6 入门教程

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值