元編程是一種強大的技術,使你能夠編寫可以創建其他程式的程式。ES6藉助代理和許多類似功能,使在JavaScript中利用元編程變得更加容易。ES6 Proxy(代理) 有助於重新定義對象的基本操作,從而為各種可能性打開了大門。 本指南可以幫助您理解為什麼ES6代理如此之好,尤其是對於元編程而言: 什 ...
本指南可以幫助您理解為什麼ES6代理如此之好,尤其是對於元編程而言:
-
什麼是ES6代理
-
如何以及何時實施代理
-
如何使用ES6代理執行訪問控制,數據綁定和緩存
-
ES6代理不是性能密集型任務的理想選擇
先決條件和結果
本教程主要針對有JavaScript經驗的開發人員,至少要熟悉ES6代理的概念。如果你已經對代理作為一種設計模式有了牢固的理解,那麼這些知識應該可以轉化為現實。
閱讀本指南後,你應該能夠:
-
瞭解什麼是ES6代理,如何實現以及何時使用它
-
使用ES6代理進行訪問控制,緩存和數據綁定
ES6代理剖析:目標(Target),處理程式(handler)和陷阱(trap)
從根本上來說,代理是指某件事或某人成為其他事物的替代品,所以不管是什麼東西,都要經過替代品才能達到真正的交易。ES6代理的工作原理也是如此。
為了有效地實現和使用ES6代理,你必須瞭解三個關鍵術語:
-
Target——代理人所替代的真正的交易,目標是站在代理背後的東西。這可以是任何對象。
-
Handler——一個包含所有代理的陷阱邏輯的對象。
-
Trap——與操作系統中的陷阱類似,此上下文中的陷阱是以某種方式提供對對象的訪問的方法(可理解為攔截行為)。
綜上所述,下麵是最簡單的實現,如果使用ES6代理,對象中不存在給定的屬性,則可以返回不同的內容。
const target = { someProp: 1 } const handler = { get: function(target, key) { return key in target ? target[key] : 'Doesn't exist!'; } } const proxy = new Proxy(target, handler); console.log(proxy.someProp) // 1 console.log(proxy.someOtherProp) // Doesn't exist!
ES6代理是一項強大的功能,可促進JavaScript中對象的虛擬化。
數據綁定:同步多個對象
由於數據綁定的複雜性,它通常很難實現。ES6代理實現雙向數據綁定的應用可以在JavaScript的MVC庫中看到,在這些庫中,當DOM發生變化時,對象會被修改。
簡而言之,數據綁定是一種將多個數據源綁定在一起以使其同步的技術。
假設存在一個名為 username
的 ``。
<input type="text" id="username" />
假設你要使此輸入的值與對象的屬性保持同步。
const inputState = { id: 'username', value: '' }
當輸入的值發生變化時,通過監聽輸入的變化事件,然後更新 inputState
的值,修改 inputState
是相當容易的。然而,反過來,在 inputState
被修改時更新輸入,則相當困難。
ES6代理可以在這種情況下提供幫助。
const input = document.querySelector('#username') const handler = { set: function(target, key, value) { if (target.id && key === 'username') { target[key] = value; document.querySelector(`#${target.id}`) .value = value; return true } return false } } const proxy = new Proxy(inputState, handler) proxy.value = 'John Doe' console.log(proxy.value, input.value) // 雙方都將印有“ John Doe”
這樣,當 inputState
更改時,input
將反映已進行的更改。結合偵聽 change
事件,這將生成 input
和 inputState
的簡單雙向數據綁定。
雖然這是一個有效的用例,但通常不建議這樣做。以後再說。
緩存:提高代碼性能
緩存是一個古老的概念,它允許非常複雜和大型的應用程式保持相對的性能。緩存是存儲某些數據的過程,以便在請求時可以更快地提供數據。緩存並不永久地存儲任何數據。緩存失效是保證緩存新鮮的過程。這是開發人員共同的苦惱。正如Phil Karlton所說:"電腦科學中只有兩件難事:緩存無效和給事物命名。"
ES6代理使緩存更加容易。例如,如果你要檢查對象中是否存在某些東西,它將首先檢查緩存並返回數據,或者如果不存在則進行其他操作以獲取該數據。
假設你需要進行很多API調用才能獲取特定信息並對其進行處理。
const getScoreboad = (player) => { fetch('some-api-url') .then((scoreboard) => { // 用記分牌做點什麼 }) }
這就意味著,每當需要一個球員的記分牌時,就必須進行一次新的調用。相反,你可以在第一次請求時緩存記分牌,隨後的請求可以從緩存中獲取。
const cache = { 'John': ['55', '99'] } const handler = { get: function(target, player) { if(target[player] { return target[player] } else { fetch('some-api-url') .then(scoreboard => { target[player] = scoreboard return scoreboard }) } } } const proxy = new Proxy(cache, handler) // 訪問緩存並使用記分牌做一些事情
這樣,僅當緩存中不包含玩家的記分牌時,才會進行API調用。
訪問控制:控制進出對象的內容
最簡單的用例是訪問控制,ES6代理的大部分內容都屬於訪問控制。
讓我們探索使用E6代理的訪問控制的一些實際應用。
1. 驗證
ES6代理最直觀的用例之一是驗證對象內部的內容,以確保對象中的數據儘可能準確。例如,如果你想強制執行產品描述的最大字元數,可以這樣做。
const productDescs = {} const handler = { set: function(target, key, value) { if(value.length > 150) { value = value.substring(0, 150) } target[key] = value } } const proxy = new Proxy(productDescs, handler)
現在,即使你添加的描述超過150個字元,也會被刪減並添加。
2. 提供對象的只讀視圖
有時候你可能要確保不以任何方式修改對象,並且只能將其用於讀取目的。 JavaScript提供了 Object.freeze()
來執行此操作,但是使用代理時,該行為更可自定義。
const importantData = { name: 'John Doe', age: 42 } const handler = { set: 'Read-Only', defineProperty: 'Read-Only', deleteProperty: 'Read-Only', preventExtensions: 'Read-Only', setPrototypeOf: 'Read-Only' } const proxy = new Proxy(importantData, handler)
現在,當你嘗試以任何方式更改對象時,你只會收到一個字元串,表示只讀。否則,你可能會引發錯誤以指示該對象是只讀的。
3. 私有屬性
JavaScript本身並沒有私有屬性,除了閉包。當 Symbol
數據類型被引入時,它被用來模仿私有屬性。但隨著Object.getOwnPropertySymbols
方法的引入,它被拋棄了。ES6代理並不是一個完美的解決方案,但在緊要關頭它們可以完成任務。
一種常見的約定是通過在名稱前加上下劃線來標識私有屬性,這個約定允許你使用ES6代理。
const object = { _privateProp: 42 } const handler = { has: function(target, key) { return !(key.startsWith('_') && key in target) }, get: function(target, key, receiver) { return key in receiver ? target[key] : undefined } } const proxy = new Proxy(object, handler) proxy._privateProp // undefined
添加 ownKeys
和 deleteProperty
會讓這個實現更接近於真正的私有屬性。然後,你仍然可以在開發者控制臺中查看代理對象。如果你的用例與上面的實現一致,它仍然適用。
為何以及何時使用代理
ES6代理並不是性能密集型任務的理想選擇。這就是為什麼進行必要的測試是至關重要的。代理可以在任何預期對象的地方使用,代理只需幾行代碼就能提供複雜的功能,這使它成為元編程的理想功能。
代理通常與另一個稱為Reflect的元編程功能一起使用。
總結
對了,小編為大家準備了一套2020最新的web前端資料,需要點擊下方鏈接獲取方式