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
的值。操作系統
另外一個對象的基本操做方法是 set
。3d
const obj = { val: 10 };
obj.val2 = 20;
這裏,set
方法用來給對象obj
設置一個新的值。code
const proxiedObject = new Proxy(initialObj, handler);
調用Proxy構造函數,new Proxy()
將返回一個對象,不只包含了initialObj
裏的值,並且其基本操做(如get
和 set
)如今能夠經過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.
自定義對象的屬性校驗
自定義校驗 - 控制檯輸出
在上面的例子中,咱們已經看到了get
和set
「陷阱」。 實際上能夠設置更多的「陷阱」。 你能夠在這裏找到整個列表。
Proxy對象只是在閱讀關於它們的這篇文章以後才進入個人視野,我已經能夠在我天天寫的代碼中看到它們的用處了!