第十二节:ES6 Proxy代理 和 去银行存款有什么关系?
????????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( )實現取消代理。
總結
以上是生活随笔為你收集整理的第十二节:ES6 Proxy代理 和 去银行存款有什么关系?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【流量】一觉醒来发现CSDN博客访问量增
- 下一篇: 第十节:实现vue组件之间的通信