亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

js中Proxy一定要配合Reflect使用的原因是什么

發布時間:2022-04-01 11:05:56 來源:億速云 閱讀:232 作者:iii 欄目:開發技術

這篇文章主要介紹“js中Proxy一定要配合Reflect使用的原因是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“js中Proxy一定要配合Reflect使用的原因是什么”文章能幫助大家解決問題。

前置知識

  • Proxy 代理,它內置了一系列”陷阱“用于創建一個對象的代理,從而實現基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數調用等)。

  • Reflect 反射,它提供攔截 JavaScript 操作的方法。這些方法與 Proxy 的方法相同。

簡單來說,我們可以通過 Proxy 創建對于原始對象的代理對象,從而在代理對象中使用 Reflect 達到對于 JavaScript 原始操作的攔截。

如果你還不了解 & ,那么趕快去 MDN 上去補習他們的知識吧。

畢竟大名鼎鼎的 VueJs/Core 中核心的響應式模塊就是基于這兩個 Api 來實現的。

單獨使用 Proxy

開始的第一個例子,我們先單獨使用 Proxy 來烹飪一道簡單的開胃小菜:

const obj = {
  name: 'wang.haoyu',
};

const proxy = new Proxy(obj, {
  // get陷阱中target表示原對象 key表示訪問的屬性名
  get(target, key) {
    console.log('劫持你的數據訪問' + key);
    return target[key]
  },
});

proxy.name // 劫持你的數據訪問name -> wang.haoyu

看起來很簡單對吧,我們通過 Proxy 創建了一個基于 obj 對象的代理,同時在 Proxy 中聲明了一個 get 陷阱。

當訪問我們訪問 proxy.name 時實際觸發了對應的 get 陷阱,它會執行 get 陷阱中的邏輯,同時會執行對應陷阱中的邏輯,最終返回對應的 target[key] 也就是所謂的 wang.haoyu .

Proxy 中的 receiver

上邊的 Demo 中一切都看起來順風順水沒錯吧,細心的同學在閱讀 Proxy 的 MDN 文檔上可能會發現其實 Proxy 中 get 陷阱中還會存在一個額外的參數 receiver 。

那么這里的 receiver 究竟表示什么意思呢?大多數同學會將它理解成為代理對象,但這是不全面的。

接下來同樣讓我們以一個簡單的例子來作為切入點:

const obj = {
  name: 'wang.haoyu',
};

const proxy = new Proxy(obj, {
  // get陷阱中target表示原對象 key表示訪問的屬性名
  get(target, key, receiver) {
    console.log(receiver === proxy);
    return target[key];
  },
});

// log: true
proxy.name;

上述的例子中,我們在 Proxy 實例對象的 get 陷阱上接收了 receiver 這個參數。

同時,我們在陷阱內部打印 console.log(receiver === proxy); 它會打印出 true ,表示這里 receiver 的確是和代理對象相等的。

所以 receiver 的確是可以表示代理對象,但是這僅僅是 receiver 代表的一種情況而已。

接下來我們來看另外一個例子:

const parent = {
  get value() {
    return '19Qingfeng';
  },
};

const proxy = new Proxy(parent, {
  // get陷阱中target表示原對象 key表示訪問的屬性名
  get(target, key, receiver) {
    console.log(receiver === proxy);
    return target[key];
  },
});

const obj = {
  name: 'wang.haoyu',
};

// 設置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj, proxy);

// log: false
obj.value

關于原型上出現的 get/set 屬性訪問器的“屏蔽”效果,我在這篇文章中進行了詳細闡述。這里我就不展開講解了。

我們可以看到,上述的代碼同樣我在 proxy 對象的 get 陷阱上打印了 console.log(receiver === proxy); 結果卻是 false 。

那么你可以稍微思考下這里的 receiver 究竟是什么呢? 其實這也是 proxy 中 get 陷阱第三個 receiver 存在的意義。

它是為了傳遞正確的調用者指向,你可以看看下方的代碼:

...
const proxy = new Proxy(parent, {
  // get陷阱中target表示原對象 key表示訪問的屬性名
  get(target, key, receiver) {
-   console.log(receiver === proxy) // log:false
+   console.log(receiver === obj) // log:true
    return target[key];
  },
});
...

其實簡單來說,get 陷阱中的 receiver 存在的意義就是為了正確的在陷阱中傳遞上下文。

涉及到屬性訪問時,不要忘記 get 陷阱還會觸發對應的屬性訪問器,也就是所謂的 get 訪問器方法。

我們可以清楚的看到上述的 receiver 代表的是繼承與 Proxy 的對象,也就是 obj。

看到這里,我們明白了 Proxy 中 get 陷阱的 receiver 不僅僅代表的是 Proxy 代理對象本身,同時也許他會代表繼承 Proxy 的那個對象。

其實本質上來說它還是為了確保陷阱函數中調用者的正確的上下文訪問,比如這里的 receiver 指向的是 obj 。

當然,你不要將 revceiver 和 get 陷阱中的 this 弄混了,陷阱中的 this 關鍵字表示的是代理的 handler 對象。

比如:

const parent = {
  get value() {
    return '19Qingfeng';
  },
};

const handler = {
  get(target, key, receiver) {
    console.log(this === handler); // log: true
    console.log(receiver === obj); // log: true
    return target[key];
  },
};

const proxy = new Proxy(parent, handler);

const obj = {
  name: 'wang.haoyu',
};

// 設置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj, proxy);

// log: false
obj.value

Reflect 中的 receiver

在清楚了 Proxy 中 get 陷阱的 receiver 后,趁熱打鐵我們來聊聊 Reflect 反射 API 中 get 陷阱的 receiver。

我們知道在 Proxy 中(以下我們都以 get 陷阱為例)第三個參數 receiver 代表的是代理對象本身或者繼承與代理對象的對象,它表示觸發陷阱時正確的上下文。

const parent = {
  name: '19Qingfeng',
  get value() {
    return this.name;
  },
};

const handler = {
  get(target, key, receiver) {
    return Reflect.get(target, key);
    // 這里相當于 return target[key]
  },
};

const proxy = new Proxy(parent, handler);

const obj = {
  name: 'wang.haoyu',
};

// 設置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj, proxy);

// log: false
console.log(obj.value);

我們稍微分析下上邊的代碼:

  • 當我們調用 obj.value 時,由于 obj 本身不存在 value 屬性。

  • 它繼承的 proxy 對象中存在 value 的屬性訪問操作符,所以會發生屏蔽效果。

  • 此時會觸發 proxy 上的 get value() 屬性訪問操作。

  • 同時由于訪問了 proxy 上的 value 屬性訪問器,所以此時會觸發 get 陷阱。

  • 進入陷阱時,target 為源對象也就是 parent ,key 為 value 。

  • 陷阱中返回 Reflect.get(target,key) 相當于 target[key]

  • 此時,不知不覺中 this 指向在 get 陷阱中被偷偷修改掉了!!

  • 原本調用方的 obj 在陷阱中被修改成為了對應的 target 也就是 parent 。

  • 自然而然打印出了對應的 parent[value] 也就是 19Qingfeng 。

這顯然不是我們期望的結果,當我訪問 obj.value 時,我希望應該正確輸出對應的自身上的 name 屬性也就是所謂的 obj.value => wang.haoyu 。

那么,Relfect 中 get 陷阱的 receiver 就大顯神通了。

const parent = {
  name: '19Qingfeng',
  get value() {
    return this.name;
  },
};

const handler = {
  get(target, key, receiver) {
-   return Reflect.get(target, key);
+   return Reflect.get(target, key, receiver);
  },
};

const proxy = new Proxy(parent, handler);

const obj = {
  name: 'wang.haoyu',
};

// 設置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj, proxy);

// log: wang.haoyu
console.log(obj.value);

上述代碼原理其實非常簡單:

  • 首先,之前我們提到過在 Proxy 中 get 陷阱的 receiver 不僅僅會表示代理對象本身同時也還有可能表示繼承于代理對象的對象,具體需要區別與調用方。這里顯然它是指向繼承與代理對象的 obj 。

  • 其次,我們在 Reflect 中 get 陷阱中第三個參數傳遞了 Proxy 中的 receiver 也就是 obj 作為形參,它會修改調用時的 this 指向。

你可以簡單的將 Reflect.get(target, key, receiver) 理解成為 target[key].call(receiver),不過這是一段偽代碼,但是這樣你可能更好理解。

相信看到這里你已經明白 Relfect 中的 receiver 代表的含義是什么了,沒錯它正是可以修改屬性訪問中的 this 指向為傳入的 receiver 對象。

js中Proxy一定要配合Reflect使用的原因是什么

關于“js中Proxy一定要配合Reflect使用的原因是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

绥阳县| 玉溪市| 神木县| 印江| 马关县| 德昌县| 隆安县| 双牌县| 东至县| 缙云县| 临夏县| 获嘉县| 库尔勒市| 九江市| 洞口县| 唐山市| 大余县| 潮州市| 改则县| 河东区| 广德县| 临泉县| 玉山县| 沂源县| 凉城县| 大安市| 佛冈县| 恩平市| 新巴尔虎左旗| 万宁市| 延吉市| 旅游| 田东县| 漳浦县| 天祝| 琼中| 弋阳县| 屏东市| 苏尼特左旗| 班戈县| 武乡县|