【ES6】第十二節:ES6 Proxy代理 和 去銀行存款有什麼關係?

轉自:微信公衆號—— web前端教程

   

 

     ES:給開發者提供了一個新特性:Proxy,就是代理的意思。也就是我們這一節要介紹的知識點。

 

        以前,ATM還沒有那麼流行的時候(暴露年紀),我們去銀行存款或者取款的時候,需要在櫃檯前排隊,等櫃檯工作人員幫我們辦理業務,這也是一種代理,我們自己無法修改我們銀行賬戶上的數據,需要代理給櫃員,幫我們辦理存錢或者取現業務,而Proxy也是這樣的一種機制。

 

Proxy的實現

        我們先來看看Proxy的實現:

 

    //定義一個對象person
    var person = {"name":"張三"};

    //創建一個代理對象pro,代理person的讀寫操作
    var pro = new Proxy(person,{
        get:function(target,property){
            return "李四"
        }
    });

    pro.name;//李四

 

        先定義一個對象,含有name屬性,值爲“張三”,創建一個代理對象pro,對象person的操作都交給代理對象pro,這不,看最後一句代碼,如果你要讀取person對象的name屬性,就要用pro.name,而不是person的name。我們看到的結果是:“李四“而不是person對象重點張三,因爲代理過程中,get方法實現了攔截的作用,不管你讀取什麼屬性,我都返回”李四“。

 

        這就是代理Proxy的作用,將一個對象交給了Proxy代理,然後通過編寫處理函數,來攔截目標對象的操作。上面的案例,你可以理解爲,person對象的name屬性值不想被別人知道是“張三“,就設置了一個代理,讓別人讀取的時候,只獲取到”李四“。

 

set方法

 

        而上面提到的“編寫處理函數“,get方法就是其中一個,除了get方法以外,還有一個很常用的是:set方法,它用於攔截對對象的寫操作。

 

        我們來結合銀行的例子,來用get方法和set方法的實現,這段代碼有點長,但是註釋很詳細,注意看代碼註釋:

 

    //定義一個對象,含有RMB和dollar屬性值
    var bankAccount = {"RMB":1000,"dollar":0};
    //創建一個Proxy代理實例
    var banker = new Proxy(bankAccount,{
        //編寫get處理程序
        get:function(target, property){
            //判斷餘額是否大於0
            if(target[property] > 0){
                //有餘額,就返回餘額值
                return target[property];
            }else{
                //沒錢了
                return "餘額不足";
            }    
        },
        //編寫set處理程序
        set:function(target,property,value){
            //存入的數額必須是一個數字類型
            if(!Number.isInteger(value)){
                return "請設置正確的數值";
            }
            //修改屬性的值
            target[property] = value;
        }
    });

    banker.RMB;
    //結果:1000
    banker.dollar;
    //結果:餘額不足

    //修改dollar屬性的值,值是字符串類型
    banker.dollar = "五百";
    banker.dollar;
    //結果:餘額不足

    //修改dollar屬性的值,值是數字類型
    banker.dollar = 500;
    banker.dollar;
    //結果:500

 

        幾乎每一句代碼都有註釋,這段代碼對應的故事情節是這樣的:老王有的銀行賬戶裏面有一些存款,其中人民幣1000元,美元0元。

 

    var bankAccount = {"RMB":1000,"dollar":0};

        

        有一天,他來到銀行櫃檯前,找到一個叫banker的工作人員,取款之前看看賬戶裏面還有多少錢,然後工作人員banker開始幫他操作(也就是代理)。

 

    banker.RMB;
    //結果:1000
    banker.dollar;
    //結果:餘額不足

 

        banker告訴他:“您賬戶裏面有人民幣1000元,可以取款的,但美元餘額不足“。

 

        接着,老王不打算取款了,打算存500美元。.

 

 

        在填寫存款單據的時候,把500不小心寫成了“五百“,banker告誡老王:”這樣是寫不行的,一定要寫阿拉伯數字,這樣寫銀行無法幫您存款的“。結果存款失敗,賬戶裏面的美元還是0元。

 

    banker.dollar = "五百";
    banker.dollar;
    //結果:餘額不足

 

        沒關係,馬上改過來,把“五百“改成500。

 

    banker.dollar = 500;
    banker.dollar;
    //結果:500

 

        存款成功,賬戶裏面的美元已有500元。

 

        故事的整個經過就是這樣,有了Proxy代理(銀行工作人員bank),幫助老王完成查看銀行存款和取款的操作(代理),避免了一些誤操作。

 

        get方法攔截了讀取操作,set方法攔截了改寫操作。Proxy除了支持以上攔截程序,還支持一系列的攔截函數,我們選擇幾個常用的講解!

 

ownKeys( )方法

 

    ownKeys攔截操作,攔截過濾Object.ownKeys()對對象的屬性遍歷。

 

    //定義一個對象person,有三個屬性
    let person = {"name":"老王","age":40,"height":1.8};

    //創建一個代理對象
    let proxy = new Proxy(person,{
        //ownKeys過濾對對象的屬性遍歷
      ownKeys:function(target){
            return ["name","age"]
        }
    });

    Object.keys(person);
    //結果:["name", "age","height"]
    
    Object.keys(proxy);
    //結果:["name", "age"]

 

        我們編寫的ownKeys方法程序,不管你有多少屬性,只返回兩個屬性name和age。我們看最後兩行代碼:Object.keys(person); 這裏我們不使用代理,直接用keys( )函數遍歷person對象,得到的person對象的原本屬性"name"、 "age"和"height"。而Object.keys(proxy) 這句代碼遍歷的是被代理的proxy對象,所以,得到的只是被過濾後的結果:[“name”,”age”]。

 

 

has( )方法

        has( )攔截操作:攔截key in object的操作,結果會返回一個布爾值。

 

    var person = {
        "name":"張三",
        "age":20
    };

    var proxy = new Proxy(person, {
        has: function(target, prop) {
            if(target[prop] === undefined){
                return false;
            }else{
                return true;
            }
        }
    });

    "name" in proxy;//結果:true
    "height" in proxy;//結果:false

 

        has( )方法用於是判斷是否含有指定的鍵值對,有,就返回true。否則返回false。

 

        對象含有name屬性,所以返回true,沒有height屬性,返回false。

 

apply( )方法

 

        除了對象類型的變量可以被代理,函數也可以被代理。如果被代理的變量是一個函數,那麼還會支持一個攔截程序:apply調用。

 

    //創建一個函數fn
    let fn = function(){
        alert('我是前端君');
    };
    //創建一個代理實例,代理函數fn
    let proxy = new Proxy(fn,{
        apply:function(){
            alert('我是隔壁老王');
        }
    });

    proxy();//結果:我是隔壁老王

 

        最後一句代碼,proxy本身是一個代理實例對象,因爲它代理的是一個函數fn,所以可以直接用函數的形式調用proxy( );當它當作函數調用的時候,就會被apply攔截,執行alert('我是隔壁老王')。

 

Proxy.revocable( )取消代理

        如果創建了代理之後又想取消代理的話,我們可以用Proxy.revocable( )函數來實現,它會返回一個對象,對象中含有一個proxy屬性,它就是Proxy的代理實例對象;還有一個revoke屬性,它是一個方法,用於取消代理。

 

        我們用實例演示一下:

 

    //定義一個對象
    let person = {"name":"張三"};
    //定義一個代理處理程序
    let handle = {
        get:function(target,prop){
            return "李四";
        }
    };

    //使用Proxy.revocable()進行代理
    let object = Proxy.revocable(person,handle);

    object.proxy.name;//結果:李四

    //調用返回對象object的revoke方法,取消代理
    object.revoke();

    object.proxy.name;//報錯,代理被取消

 

        這個案例大家要注意的是Proxy.revocable( )方法返回的結果,它是一個對象,在控制檯打印出來後的結果是:Object{ proxy:Object , revoke:function(){....} }。有一個proxy屬性,它就是Proxy代理實例,還有一個屬性revoke,它是一個方法,專用於取消代理。

 

        我們使用object.proxy.name來讀取name的屬性,由於被代理攔截了,只能讀取到“李四”,接着我們調用revoke( )方法取消代理,然後再使用object.proxy.name的時候就會報錯了,代理已經不存在了。

 

        以上就是Proxy代理的介紹,關於其他的攔截操作就不一一介紹,包括:

 

  • defineProperty( )

  • deleteProperty( )

  • enumerate( )

  • getOwnPropertyDescriptor( )

  • getPrototypeOf( )

  • isExtensible( )

  • preventExtensions( )

  • setPrototypeOf( )

     

 

 

本節小結

總結:ES6帶了的Proxy代理機制,它提供了一些攔截操作:set、get、apply、has、ownKeys等,我們可以根據需求編寫攔截程序,達到我們想要的效果;此外,還可以利用Proxy.revocable( )實現取消代理。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章