ES6中Proxy和Reflect的理解和用法

Proxy

在教程中對(duì)于Proxy的定義是這樣的,Proxy用于修改某些操作的默認(rèn)行為,即對(duì)編程語(yǔ)言層面進(jìn)行修改,屬于“元編程”,Proxy意思為“代理”,即在訪問(wèn)對(duì)象之前建立一道“攔截”,任何訪問(wèn)該對(duì)象的操作之前都會(huì)通過(guò)這道“攔截”,即執(zhí)行Proxy里面定義的方法。

(1)ES6原生規(guī)定的Proxy的基本用法為

 let pro = new Proxy(target,handler);

其中 new Proxy相當(dāng)于創(chuàng)建了一個(gè)Proxy實(shí)例,target為所要攔截的目標(biāo)對(duì)象,handler也是一個(gè)對(duì)象,里面定義的是對(duì)攔截對(duì)象所要進(jìn)行的攔截方法。

Proxy實(shí)例1

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

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

let pro = new Proxy(target,handler);

console.log(pro.name);
//此時(shí)打印出來(lái)的結(jié)果為 success;

解釋:創(chuàng)建的target對(duì)象為所要攔截的對(duì)象,handler對(duì)象為攔截對(duì)象后執(zhí)行的操作,這里get方法為讀取操作,即用戶想要讀取pro中的屬性時(shí)執(zhí)行的攔截操作。最后創(chuàng)建一個(gè)Proxy實(shí)例,因?yàn)槲以O(shè)定的讀取攔截操作為返回一個(gè)“success”字符串,所以當(dāng)我想讀取pro中的屬性時(shí),結(jié)果打印出來(lái)的總是“success”字符串。

Proxy實(shí)例2

let target = {
     name:"小明",
     age:15
};
let handler = {};
let pro = new Proxy(target,handler);

console.log(pro.name);
//結(jié)果為 小明

pro.name = "小紅";
console.log(pro.name);
//結(jié)果為 小紅

解釋:攔截操作對(duì)象handler為空,未對(duì)攔截對(duì)象設(shè)定攔截方法,該情況下pro直接指向原對(duì)象target,訪問(wèn)pro等同于訪問(wèn)target,所以結(jié)果為target中的結(jié)果。

Proxy實(shí)例3

Proxy也可以作為其他對(duì)象的原型對(duì)象使用

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);
//打印結(jié)果為  success

解釋:上述實(shí)例將pro作為obj的原型對(duì)象使用,雖然obj本身沒(méi)有name這個(gè)屬性,但是根據(jù)原型鏈,會(huì)在pro上讀取到name屬性,之后會(huì)執(zhí)行相對(duì)應(yīng)的攔截操作。

(2)Proxy常用的攔截方法

1、get(target,name,property)方法,用于攔截某個(gè)讀取屬性的操作,第一個(gè)參數(shù)為目標(biāo)對(duì)象,第二個(gè)參數(shù)為屬性名稱,第三個(gè)屬性為操作所針對(duì)的對(duì)象(可選參數(shù))。

      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;
     //結(jié)果為 success
      pro.grade;
      //結(jié)果為error

2、set(target,name,value,property),用于攔截某個(gè)屬性的賦值操作,第一個(gè)參數(shù)為目標(biāo)對(duì)象,第二個(gè)參數(shù)為屬性名,第三個(gè)參數(shù)為屬性值,第四個(gè)參數(shù)為操作行為所針對(duì)的對(duì)象(可選參數(shù))。

     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;
      //結(jié)果為 success,并且返回修改值
      
      pro.age = "12";
      //結(jié)果為error,拋出錯(cuò)誤

3、has(target,key),用來(lái)攔截對(duì)象是否具有某個(gè)屬性值的操作,第一個(gè)參數(shù)為目標(biāo)對(duì)象,第二個(gè)參數(shù)為屬性名

       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);
      //打印結(jié)果為 true
      
     console.log("age" in pro);
      //打印結(jié)果為false

Reflect對(duì)象

概述

1、Reflect對(duì)象與Proxy對(duì)象一樣,都是ES6對(duì)操作對(duì)象設(shè)計(jì)的API
2、對(duì)于我個(gè)人的理解而言,Reflect設(shè)計(jì)的目的是為了優(yōu)化Object的一些操作方法以及合理的返回Object操作返回的結(jié)果,對(duì)于一些命令式的Object行為,Reflect對(duì)象可以將其變?yōu)楹瘮?shù)式的行為

實(shí)例1

//舊寫(xiě)法
try{
   Object.defineProperty(target,name,property);

}catch(e){
   console.log("error");
}

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

實(shí)例2

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

//舊寫(xiě)法
console.log(name in obj);
//結(jié)果為 true
    
//Reflect對(duì)象操作
console.log(Reflect.has(obj,"name"));
//結(jié)果為 true

實(shí)例3
因?yàn)镽eflect對(duì)象的操作和Proxy對(duì)象的操作是一一對(duì)應(yīng)的,所以在Proxy的攔截操作中,可以直接利用Reflect對(duì)象直接獲取Proxy的默認(rèn)值

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)
//結(jié)果為
// success
//小明

Reflect的靜態(tài)方法

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對(duì)象的靜態(tài)方法和Proxy對(duì)象的靜態(tài)方法一一對(duì)應(yīng),所以在功能上也相同,不一一列舉了
如果要查閱對(duì)應(yīng)方法的用法實(shí)例,參照阮一峰老師的ES6語(yǔ)法http://es6.ruanyifeng.com/#docs/reflect

實(shí)例:使用Proxy實(shí)現(xiàn)觀察者模式

觀察者模式(Observer mode)指的是函數(shù)自動(dòng)觀察數(shù)據(jù)對(duì)象,一旦數(shù)據(jù)有變化,函數(shù)就會(huì)自動(dòng)執(zhí)行

//初始化觀察者隊(duì)列
const arr = new Set();

//將監(jiān)聽(tīng)函數(shù)加入隊(duì)列
const obe = fun => {
  arr.add(fun);
}

//初始化Proxy對(duì)象,設(shè)置攔截操作
const observable =  obj => new Proxy(obj, {set});

function set(target, key, value, receiver){
     //內(nèi)部調(diào)用對(duì)應(yīng)的 Reflect 方法
     const result = Reflect.set(target, key, value, receiver);
     //額外執(zhí)行觀察者隊(duì)列
     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 = "小紅"
 //結(jié)果   小紅,15
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 來(lái)自深入理解ES6第十二章,由于最近業(yè)務(wù)中經(jīng)常用到,記錄一下 這里內(nèi)容都太學(xué)術(shù)了,有一篇簡(jiǎn)單介紹Proxy作用的文...
    NowhereToRun閱讀 1,098評(píng)論 0 1
  • Proxy Proxy可以理解成,在目標(biāo)對(duì)象之前架一層‘?dāng)r截’,外界對(duì)該對(duì)象的訪問(wèn),都必須先通過(guò)這層攔截,因此提供...
    nomooo閱讀 1,103評(píng)論 0 4
  • defineProperty() 學(xué)習(xí)書(shū)籍《ECMAScript 6 入門(mén) 》 Proxy Proxy 用于修改某...
    Bui_vlee閱讀 708評(píng)論 0 1
  • 1 昨晚,喵小姐和魚(yú)先生大吵一架。 原因是魚(yú)先生和喵小姐現(xiàn)在租住的這套房子,實(shí)在是太老了,魚(yú)先生想換一套房子租,喵...
    亦暖橙閱讀 699評(píng)論 2 7
  • 投射我兒早睡早起,注意面部衛(wèi)生,臉上的毛囊炎好了,面部也光滑如初。 投射我兒在校認(rèn)真聽(tīng)課,努力學(xué)習(xí),有計(jì)劃,有目標(biāo)...
    花開(kāi)生兩面閱讀 155評(píng)論 0 0

友情鏈接更多精彩內(nèi)容