最簡單的proxy講解,一遍就懂

Day 9

代理與反射

代理基礎:

  • 代理是目標對象的抽象,能夠當作是目標對象的替身,但徹底獨立於目標對象,目標對象能夠被直接操做,也能夠經過代理來操做

建立空代理:

  • 最簡單的代理是空代理,就是說除了做爲一個抽象的目標對象,什麼也不作,在代理對象是執行的全部操做都會無障礙的傳播到目標對象,所以,任何使用目標對象的地方,均可以經過一樣的方式使用與之關聯的代理對象markdown

    例子1:函數

const target = { id: 'target' };
const handler = {}; const proxy = new Proxy(target, handler); // id屬性會訪問同一個值 console.log(target.id); // target  console.log(proxy.id); // target  // 給目標屬性賦值會反映在兩個對象上, 由於兩個對象訪問的是同一個值 target.id = 'foo'; console.log(target.id); // foo console.log(proxy.id); // foo  // 給代理屬性賦值會反映在兩個對象上,由於這個賦值會轉移到目標對象 proxy.id = 'bar'; console.log(target.id); // bar console.log(proxy.id); // bar  // hasOwnProperty()方法在兩個地方 都會應用到目標對象 console.log(target.hasOwnProperty('id')); // true  console.log(proxy.hasOwnProperty('id')); // true 複製代碼

小結:這是最簡單的一個空代理的案例,初看可能會不明因此,我當初看也很懵,可是不要着急,你如今只須要看懂,知道代理作了什麼事情,在這個例子裏,target是代理的目標,proxy是代理,代理的目標和代理屬性共享,操做共享,包括方法也是共享的,可是代理並不等於代理目標,更傾向於操做代理時,代理把操做轉發給了代理的目標,而後進行操做,目標擁有的,代理會擁有,代理擁有的,也會相應的傳遞給目標;oop

代碼捕獲器與反射方法:

  • 使用代理的目的 :是能夠定義捕獲器(trap),捕獲器就是能夠直接或間接在代理對象上調用,每次在代理對象上調用這些基本操做時, 代理能夠在這些操做傳播到目標對象以前先調用捕獲器函數,從而攔 截並修改相應的行爲。ui

    • 通俗講就是,捕獲器在代理對象被調用時,先執行,從而攔截而且修改相應的行爲,就是相似加了一層if判斷,或者說是彈框確認
  • handler :代理的處理對象,例子1中是一個空對象,多數狀況下並非空對象,而是定義了一個或者多個捕獲器(trap)去處理代理,若是沒有定義,則和上例中的空對象同樣,使用默認行爲。this

  • set trap :經常使用的trap,觸發條件是在設置屬性值的時候觸發,spa

  • Reflect.set: 將值分配給屬性的函數。返回一個Boolean,若是更新成功,則返回true代理

    首先set trap接受4個參數,code

    • trapTarget - 接收的屬性的對象,就是**代理的目標 **orm

    • key - 要寫入的屬性的對象

    • value- 寫入屬性的

    • receiver- 操做的對象,一般是代理

      例子2:用set trap驗證一個屬性的值是否爲number

let target = {
 name: "target"  };   let proxy = new Proxy(target, {  //target,name,target,proxy;  set(trapTarget, key, value, receiver) {  console.log(`trapTarget is ${trapTarget}, key is ${key}, value is ${value}, receiver is ${receiver}`)  // 忽視存在的屬性,以避免產生影響,不存在的屬性纔會進入判斷  if (!trapTarget.hasOwnProperty(key)) {  //判斷值是否爲number  if (isNaN(value)) {  throw new TypeError("Property must be a number.");  }  }  // 添加到屬性  return Reflect.set(trapTarget, key, value, receiver);  }  });  // 添加一個新的屬性  proxy.count = 1;  console.log(proxy.count); // 1  console.log(target.count); // 1  // 賦值給存在target上的屬性  proxy.name = "proxy";  console.log(proxy.name); // "proxy"  console.log(target.name); // "proxy"  // 新的屬性值不是數字會拋出異常  proxy.anotherName = "proxy"; 複製代碼
小結:這個例子打印出了4個參數的時刻變化,能夠清晰的看到參數對應的值,能夠發現,每次設置屬性值的時候都會進行攔截判斷,因此在獲取時候,能夠用get進行攔截判斷,
複製代碼
  • get trap:

    • get 是讀取對象屬性的時候用到的trap,他接受3個參數

    • trapTarget: 從哪一個對象讀取的屬性,就是target

    • key - 讀取的key

    • receiver - 操做的對象,一般是代理(proxy)

      例子1:這是一個普通的get代理的按理

const handler = {
 get: function(obj, prop) {  return prop in obj ? obj[prop] : 37;  }  };   const p = new Proxy({}, handler);  p.a = 1;  p.b = undefined;   console.log(p.a, p.b); // 1, undefined  console.log('c' in p, p.c); // false, 37 複製代碼
小結:p.a的時候,獲取代理裏面a的值通過get,返回了 a的值,p.b同樣,而後c in p,由於p沒有c這個屬性,因此會返回false,p.c像p獲取c屬性,進入get,賦值爲37,
複製代碼
  • 再來看一個set 和get的綜合例子

    例子3;

var p = {
 name:"chen",  work:function() {  console.log("wording...");  },  _age:18,  //監聽獲取name屬性的事件  get name(){  return this._age;  },  //監聽設置age屬性的事件  set age(val) {  if (val<0 || val> 100) {//若是年齡大於100就拋出錯誤  throw new Error("invalid value")  }else{  this._age = val;  }  }  };  console.log(p.name);//輸出18,由於這裏觸發了監聽name屬性的攔截,因此返回的age,  console.log(p._age);//這裏的age沒有獲取攔截,因此輸出原值  console.log(p._age =20);//輸出20,由於這裏進入設置攔截,知足條件,完成賦值  console.log(p._age =200);//報錯,設置攔截進入,不知足條件,報錯  console.log(p.name = 'yu')//輸出 yu,由於name沒有設置攔截,因此能夠成功 複製代碼

小結:看完這個,代理的基本知識及其原理相信你們都明白了,其實捕獲器還有不少,列如has等等,可是基本原理都是這樣,只要把握住參數分別表明什麼,捕獲器的觸發條件,問題均可以迎刃而解了,但願能夠給你們帶來幫助

本文使用 mdnice 排版

相關文章
相關標籤/搜索