今天咱們要學習的是ECMAScript 6的代理。咱們將在本文中涉及如下主題。vue
讓咱們開始吧:)git
如MDN網站所述。github
Proxy
對象使你可以爲另外一個對象建立一個代理,它能夠攔截和從新定義該對象的基本操做。
他們在解釋什麼是代理的時候,說它能夠建立一個代理**,這有點搞笑。固然,他們並無錯,但咱們能夠簡化這個說法,使其更加友好,說設計模式
_Proxy_
對象可讓你包裹目標對象,經過這樣作,咱們能夠攔截和從新定義該對象的基本操做。
基本上,它的意思是咱們要把一個對象,用Proxy包裹起來,這將容許咱們建立一個 "隱藏 "的門,並控制全部對所需對象的訪問。瀏覽器
一個小插曲,Proxy也是一種軟件設計模式,你必定要閱讀一下(維基百科連接)。緩存
const target = { message1: "hello", message2: "everyone" }; const handler = {}; const proxy = new Proxy(target, handler);
handler
:定義哪些操做將被攔截,以及如何從新定義被攔截的操做的對象,也能夠調用 "陷阱"。大多數瀏覽器都支持代理,但也有一些老的瀏覽器不支持(固然是IE),你能夠查看完整的列表這裏。google有一個polyfill的Proxies,但它不支持全部的Proxy功能。服務器
如今咱們知道了什麼是代理,咱們想看看咱們能用它作什麼。app
讓咱們想象一下,咱們是A Bank。咱們想知道每次銀行帳戶餘額被訪問並被通知上。咱們將使用最簡單的handler操做/陷阱。getdom
在上面的例子中,咱們有一個銀行帳戶對象,裏面有個人名字和2020的餘額。函數
const bankAccount = { balance: 2020, name: 'Georgy Glezer' }; const handler = { get: function(target, prop, receiver) { if (prop === 'balance') { console.log(`Current Balance Of: ${target.name} Is: ${target.balance} `); } return target[prop]; } }; const wrappedBankAcount = new Proxy(bankAccount, handler); wrappedBankAcount.balance; // access to the balance // OUTPUT: // Current Balance Of: Georgy Glezer Is: 2020 // 2020
此次的處理者對象實現的是get操做/陷阱,它接收一個有3個參數的函數和get的返回值。
咱們定義了一個條件,若是被訪問的屬性是"_balance"_,咱們將通知(log)餘額和當前用戶名,並返回屬性_"balance"_。
從輸出中能夠看到,一旦 "餘額 "屬性被訪問,咱們經過使用代理和設置get操做/陷阱,很容易就通知(log)了此次訪問。
咱們繼續用咱們Bank的想法,要求每次有人從銀行帳戶中取錢,咱們都要通知一下。而另外一個約束條件是,銀行不容許出現負餘額。爲了達到這個目的,咱們此次要使用set處理程序/陷阱。
在上面的例子中,咱們通知當前的餘額和取款後的新餘額,若是新的餘額爲負數,咱們也會通知並停止取款操做。
const bankAccount = { balance: 2020, name: 'Georgy Glezer' }; const handler = { set: function (obj, prop, value) { console.log(`Current Balance: ${obj.balance}, New Balance: ${value}`); if (value < 0) { console.log(`We don't allow Negative Balance!`); return false; } obj[prop] = value; return true; } }; const wrappedBankAcount = new Proxy(bankAccount, handler); wrappedBankAcount.balance -= 2000; // access to the balance console.log(wrappedBankAcount.balance); wrappedBankAcount.balance -= 50; // access to the balance console.log(wrappedBankAcount.balance); // OUTPUT: // Current Balance: 2020, New Balance: 20 // 20 // Current Balance: 20, New Balance: -30 // We don't allow Negative Balance! // 20
咱們使用的是set operator/trap,它是一個返回布爾值(true/false)的函數,用來判斷更新操做是否成功。它接收如下參數。
set()
處理程序也能夠經過原型鏈或其餘各類方式間接調用。你能夠看到,它其實和get很類似,但只是多接收了1個新值的參數。
這2個操做符/陷阱是最多見的,若是你有興趣找到全部現有的操做符/陷阱,你能夠查看這裏。
許多流行的庫都使用了這種技術,例如: * [MobX]()
還有更多......他們中的大多數人都利用了Proxies給咱們帶來的驚人力量,併爲咱們提供了很棒的庫。
咱們已經看到,咱們可使用代理服務器來進行。
咱們將再次使用get操做符/陷阱,並將 "dollars "屬性添加到咱們的對象中。在每次訪問 "dollars "屬性時,咱們將計算咱們的餘額價值多少美圓。由於計算是一個繁重的操做,因此咱們但願儘量的Cache它。
const bankAccount = { balance: 10, name: 'Georgy Glezer', get dollars() { console.log('Calculating Dollars'); return this.balance *3.43008459; } }; let cache = { currentBalance: null, currentValue: null }; const handler = { get: function (obj, prop) { if (prop === 'dollars') { let value = cache.currentBalance !== obj.balance ? obj[prop] : cache.currentValue; cache.currentValue = value; cache.currentBalance = obj.balance; return value; } return obj[prop]; } }; const wrappedBankAcount = new Proxy(bankAccount, handler); console.log(wrappedBankAcount.dollars); console.log(wrappedBankAcount.dollars); console.log(wrappedBankAcount.dollars); console.log(wrappedBankAcount.dollars); // OUTPUT: // Calculating Dollars // 34.3008459 // 34.3008459 // 34.3008459 // 34.3008459
正如你在例子中所看到的,咱們有一個緩存對象,它保存着當前的銀行餘額和以美圓爲單位的餘額價值。每次有人訪問"_dollars"_屬性時,咱們都會先進行計算,而後將其緩存起來。
咱們想在每次餘額發生變化時更新屏幕上的文字。咱們將使用一個set操做符/陷阱,在每次改變數值時,咱們將更新屏幕上的DOM元素。
const bankAccount = { balance: 2020, name: "Georgy Glezer", get text() { return `${this.name} Balance Is: ${this.balance}`; } }; const objectWithDom = (object, domId) => { const handler = { set: function (obj, prop, value) { obj[prop] = value; document.getElementById(domId).innerHTML = obj.text; return true; } }; return new Proxy(object, handler); }; // create a dom element with id: bank-account const wrappedBankAccount = objectWithDom(bankAccount, "bank-account"); wrappedBankAccount.balance = 26; wrappedBankAccount.balance = 100000;
在這裏,咱們建立了一個輔助函數,這樣咱們就能夠存儲DOM元素的ID,並在set operator/trap中添加了簡單的行來更新DOM元素。很簡單,對吧?讓咱們看看結果:)
綜上所述,咱們瞭解了ECMAScript 6 Proxies,咱們如何使用它們,以及用於什麼目的。在我看來,Proxies是一個很神奇的工具,你能夠用它來作各類各樣的選擇,你只須要想一想什麼最適合你:) 。
若是您喜歡這篇文章,歡迎關注並拍手👏。