Javascript Proxy對象 簡介

Javascript Proxy對象 簡介

 

Javascript Proxy對象javascript

 

改變你操做對象的方式java

Proxies 是Javasript對象的中間件函數

...或者說至少是那種很早的版本。this

ES6 中引入Proxies,讓你能夠自定義Object的基本操做。例如,get就是Object的基礎操做方法。spa

const obj = {
   val: 10
};
console.log(obj.val);

這裏,console.log()表達式在對象obj上執行get方法來獲取val的值。操作系統

另外一個對象的基本操做方法是 set3d

const obj = {
   val: 10
};
obj.val2 = 20;

這裏,set方法用來給對象obj設置一個新的值。code

如何建立Proxy?

const proxiedObject = new Proxy(initialObj, handler);

調用Proxy構造函數,new Proxy()將返回一個對象,不只包含了initialObj裏的值,並且其基本操做(如getset)如今能夠經過handler對象來指定一些自定義邏輯。中間件

咱們寫個例子來理解這個概念,對象

const handler = {
    get: function() {
        console.log('A value has been accessed');
    }
}

const initialObj = {
    id: 1,
    name: 'Foo Bar'
}

const proxiedObj = new Proxy(initialObj, handler);

console.log(proxiedObj.name);

如今,若是咱們沒有構造一個Proxy對象,執行第14行的console.log(proxiedObj.name)會在控制檯輸出 「Foo Bar」。

不過如今咱們定義了一個Proxy,並在第三行get方法中定義了一些自定義邏輯。

如今執行console.log(proxiedObj.name)會在控制檯輸出 「A value has been accessed」。

仔細看,你會發現控制檯中實際上有兩條記錄。 「A value has been accessed」 和 undefined。 爲何?

get運算符的默認實現是返回Object中存儲的值。因爲咱們將它重寫爲只記錄一條語句,該值永遠不會返回,所以第14行的console.log()輸出undefined

讓咱們來解決這個問題!

get運算符有兩個參數 - 對象自己和被訪問的屬性。

const handler = {
    get: function(obj, prop) {
        console.log('A value has been accessed');
        return obj[prop]; // 返回訪問的key在obj的值
    }
}

const initialObj = {
    id: 1,
    name: 'Foo Bar'
}

const proxiedObj = new Proxy(initialObj, handler);

console.log(proxiedObj.name);

返回屬性值

返回屬性值 --- 控制檯的輸出

 

好多了吧!

咱們爲get提供的自定義覆蓋被稱爲「攔截器」(大概基於操做系統攔截的概念)。 handler對象基本上是一個包含一組「攔截」的對象,每當訪問對象屬性時都會被觸發。

咱們給set也添加一個「攔截器」。 咱們將作一樣的事情 - 任什麼時候候設置一個值,咱們將記錄被修改的屬性,以及爲該鍵設置的值。

set操做符有三個參數 - 對象自己,被訪問的屬性和爲該屬性設置的值。

const handler = {
    get: function(obj, prop) {
        console.log('A value has been accessed');
        return obj[prop];
    },
    set: function(obj, prop, value) {
        console.log(`${prop} is being set to ${value}`);
    }
}

const initialObj = {
    id: 1,
    name: 'Foo Bar'
}

const proxiedObj = new Proxy(initialObj, handler);

proxiedObj.age = 24

添加`set` 「攔截器」

這裏,在第18行進行的訪問將觸發第6行定義的功能,該功能將記錄正在訪問的屬性和正在設置的值。

`Set` 「攔截器」 —— 控制檯的輸出

一個真實的例子

假設咱們有一個定義叫person的對象

const person = {
   id: 1,
   name: 'Foo Bar'
};

若是咱們想讓這個對象的id屬性是一個私有屬性呢? 沒人可以經過person.id訪問這個屬性,若是有人這樣作,咱們須要拋出一個錯誤。 咱們將如何作到這一點?

讓Proxies來拯救吧!‍

咱們所須要作的就是給這個對象建立一個Proxy,並覆蓋get運算符來阻止咱們訪問id屬性!

const handler = {
    get: function(obj, prop) {
        if (prop === 'id') { // Check if the id is being accessed
            throw new Error('Cannot access private properties!'); // Throw an error
        } else {
            return obj[prop]; // If it's not the id property, return it as usual
        }
    }
}

const person = {
    id: 1,
    name: 'Foo Bar'
}

const proxiedPerson = new Proxy(person, handler);

console.log(proxiedPerson.id);

阻止訪問私有屬性

這裏,在咱們給get建立的「攔截器」,咱們檢查被訪問的屬性是不是id屬性,若是是的話,咱們會拋出一個錯誤。 不然,咱們照常返回值。

私有屬性 — 控制檯輸出

另外一個極好的用例是校驗。 經過設置set「攔截器」,咱們能夠在設置值以前添加自定義驗證。 若是該值不符合驗證,咱們能夠拋出一個錯誤!

const handler = {
    set: function(obj, prop, value) {
        if (typeof value !== 'string') {
            throw new Error('Only string values can be stored in this object!');
        } else {
            obj[prop] = value;
        }
    }
}

const obj = {};

const proxiedObj = new Proxy(obj, handler);

console.log(proxiedObj); // This will log an empty object
proxiedObj.name = 'Foo Bar'; // This should be allowed
console.log(proxiedObj); // This will log an object with the name property set

proxiedObj.age = 24; // This will throw an error.

自定義對象的屬性校驗

自定義校驗 - 控制檯輸出

在上面的例子中,咱們已經看到了getset「陷阱」。 實際上能夠設置更多的「陷阱」。 你能夠在這裏找到整個列表

Proxy對象只是在閱讀關於它們的這篇文章以後才進入個人視野,我已經能夠在我天天寫的代碼中看到它們的用處了!

相關文章
相關標籤/搜索