ES6標準入門讀書筆記11(Proxy)

? ? ? ?

? ? ? ? Proxy 可以理解成,在目標對象之前架設(shè)一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,可以譯為“代理器”。

ES6 原生提供 Proxy 構(gòu)造函數(shù),用來生成 Proxy 實例。

var proxy = new Proxy(target, handler);

Proxy 對象的所有用法,都是上面這種形式,不同的只是handler參數(shù)的寫法。其中,new Proxy()表示生成一個Proxy實例,target參數(shù)表示所要攔截的目標對象,handler參數(shù)也是一個對象,用來定制攔截行為。

下面是另一個攔截讀取屬性行為的例子。

var proxy = new Proxy({}, {
? get: function(target, property) {
? ? return 35;
? }
});
proxy.time // 35
proxy.name // 35
proxy.title // 35

上面代碼中,作為構(gòu)造函數(shù),Proxy接受兩個參數(shù)。第一個參數(shù)是所要代理的目標對象(上例是一個空對象),即如果沒有Proxy的介入,操作原來要訪問的就是這個對象;第二個參數(shù)是一個配置對象,對于每一個被代理的操作,需要提供一個對應的處理函數(shù),該函數(shù)將攔截對應的操作。比如,上面代碼中,配置對象有一個get方法,用來攔截對目標對象屬性的訪問請求。get方法的兩個參數(shù)分別是目標對象和所要訪問的屬性。可以看到,由于攔截函數(shù)總是返回35,所以訪問任何屬性都得到35。

注意,要使得Proxy起作用,必須針對Proxy實例(上例是proxy對象)進行操作,而不是針對目標對象(上例是空對象)進行操作。

如果handler沒有設(shè)置任何攔截,那就等同于直接通向原對象。

var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"

Proxy 實例也可以作為其他對象的原型對象。

var proxy = new Proxy({}, {
? get: function(target, property) {
? ? return 35;
? }
});
let obj = Object.create(proxy);
obj.time // 35

圖片發(fā)自簡書App

2.Proxy 實例的方法

get()

get方法用于攔截某個屬性的讀取操作,可以接受三個參數(shù),依次為目標對象、屬性名和 proxy 實例本身(嚴格地說,是操作行為所針對的對象),其中最后一個參數(shù)可選。

get方法的用法,上文已經(jīng)有一個例子,下面是另一個攔截讀取操作的例子。

var person = {
? name: "張三"
};
var proxy = new Proxy(person, {
? get: function(target, property) {
? ? if (property in target) {
? ? ? return target[property];
? ? } else {
? ? ? throw new ReferenceError("Property \"" + property + "\" does not exist.");
? ? }
? }
});
proxy.name // "張三"
proxy.age // 拋出一個錯誤

上面代碼表示,如果訪問目標對象不存在的屬性,會拋出一個錯誤。如果沒有這個攔截函數(shù),訪問不存在的屬性,只會返回undefined。

set() § ?

set方法用來攔截某個屬性的賦值操作,可以接受四個參數(shù),依次為目標對象、屬性名、屬性值和 Proxy 實例本身,其中最后一個參數(shù)可選。

假定Person對象有一個age屬性,該屬性應該是一個不大于 200 的整數(shù),那么可以使用Proxy保證age的屬性值符合要求。

let validator = {
? set: function(obj, prop, value) {
? ? if (prop === 'age') {
? ? ? if (!Number.isInteger(value)) {
? ? ? ? throw new TypeError('The age is not an integer');
? ? ? }
? ? ? if (value > 200) {
? ? ? ? throw new RangeError('The age seems invalid');
? ? ? }
? ? }
? ? // 對于滿足條件的 age 屬性以及其他屬性,直接保存
? ? obj[prop] = value;
? }
};
let person = new Proxy({}, validator);
person.age = 100;
person.age // 100
person.age = 'young' // 報錯
person.age = 300 // 報錯

有時,我們會在對象上面設(shè)置內(nèi)部屬性,屬性名的第一個字符使用下劃線開頭,表示這些屬性不應該被外部使用。結(jié)合get和set方法,就可以做到防止這些內(nèi)部屬性被外部讀寫。

const handler = {
? get (target, key) {
? ? invariant(key, 'get');
? ? return target[key];
? },
? set (target, key, value) {
? ? invariant(key, 'set');
? ? target[key] = value;
? ? return true;
? }
};
function invariant (key, action) {
? if (key[0] === '_') {
? ? throw new Error(`Invalid attempt to ${action} private "${key}" property`);
? }
}
const target = {};
const proxy = new Proxy(target, handler);
proxy._prop
// Error: Invalid attempt to get private "_prop" property
proxy._prop = 'c'

apply()

apply方法攔截函數(shù)的調(diào)用、call和apply操作。

apply方法可以接受三個參數(shù),分別是目標對象、目標對象的上下文對象(this)和目標對象的參數(shù)數(shù)組。

var handler = {
? apply (target, ctx, args) {
? ? return Reflect.apply(...arguments);
? }
};
var target = function () { return 'I am the target'; };
var handler = {
? apply: function () {
? ? return 'I am the proxy';
? }
};
var p = new Proxy(target, handler);
p()
// "I am the proxy"
var twice = {
? apply (target, ctx, args) {
? ? return Reflect.apply(...arguments) * 2;
? }
};
function sum (left, right) {
? return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • defineProperty() 學習書籍《ECMAScript 6 入門 》 Proxy Proxy 用于修改某...
    Bui_vlee閱讀 706評論 0 1
  • 看這本書是在markdown在做的筆記,更友好的閱讀方式訪問: github es6.md(https://git...
    汪汪仙貝閱讀 514評論 0 0
  • 實習生安排首先要設(shè)一個具體的要求,在實習結(jié)束后,我希望達成的一個目標 1 希望能了解基本的邏輯 2能幫忙處理一些例...
    一蠻牛閱讀 582評論 0 0
  • 來了去了,濃了淡了,近了遠了 都像一縷風,過往無聲 一花一世界,一葉一菩提,花葉總會分離 風雨旅程,變幻萬千,一句...
    四夕清荷閱讀 393評論 0 1
  • 和珅書法賞析 、 說明: 1.本文內(nèi)容為吉祥轉(zhuǎn)載,版權(quán)歸作者所有。圖片來自于網(wǎng)絡,版權(quán)歸作者所有。 2.吉祥書畫網(wǎng)...
    吉祥書畫館閱讀 1,909評論 0 0

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