明天咱们要学习的是 ECMAScript 6 的 代理。咱们将在本文中波及以下主题。
- 什么是代理
- 代理人在口头
- 谁应用代理
- 应用案例和实例
- 资源
让咱们开始吧:)
什么是代理
如 MDN 网站所述。
Proxy
对象使你可能为另一个对象创立一个代理,它能够拦挡和从新定义该对象的基本操作。
他们在解释什么是 代理的时候,说它能够创立一个 代理 **,这有点搞笑。当然,他们并没有错,但咱们能够简化这个说法,使其更加敌对,说
_Proxy_
对象能够让你包裹指标对象,通过这样做,咱们能够拦挡和从新定义该对象的基本操作。
基本上,它的意思是咱们要把一个对象,用 Proxy 包裹起来,这将容许咱们创立一个 “ 暗藏 “ 的门,并管制所有对所需对象的拜访。
一个小插曲,Proxy也是一种软件设计模式,你肯定要浏览一下(维基百科链接)。
const target = {
message1: "hello",
message2: "everyone"
};
const handler = {};
const proxy = new Proxy(target, handler);
一个 “ 代理 “ 是用两个参数创立的。
- “target”:你要包裹的原始对象(代理)。
handler
:定义哪些操作将被拦挡,以及如何从新定义被拦挡的操作的对象,也能够调用 “ 陷阱 ”。
大多数浏览器都反对代理,但也有一些老的浏览器不反对(当然是 IE),你能够查看残缺的列表这里。google 有一个 polyfill 的 Proxies,但它不反对所有的 Proxy 性能。
当初咱们晓得了什么是 代理,咱们想看看咱们能用它做什么。
代理人在口头
让咱们设想一下,咱们是 A Bank。咱们想晓得每次银行账户余额被拜访并被告诉上。咱们将应用最简略的 handler 操作 / 陷阱。get
在下面的例子中,咱们有一个银行账户对象,外面有我的名字和 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 的返回值。
- target。被拜访的对象(咱们封装的对象)。
- prop: 被拜访的属性。在咱们的例子中被拜访的属性 – 这里是 “balance”。
- receiver:接受者。能够是代理,也能够是继承自代理的对象。
咱们定义了一个条件,如果被拜访的属性是 ”_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) 的函数,用来判断更新操作是否胜利。它接管以下参数。
- target: 被拜访的对象(咱们封装的对象)。
- prop:正在拜访的对象(咱们封装的对象)。在咱们的例子中,被拜访的属性是 “balance”。
- value。应该更新的新值。
- receiver*: 原先被调配到的对象。这通常是代理自身。但
set()
处理程序也能够通过原型链或其余各种形式间接调用。
你能够看到,它其实和 get 很类似,但只是多接管了 1 个新值的参数。
这 2 个操作符 / 陷阱是最常见的,如果你有趣味找到所有现有的操作符 / 陷阱,你能够查看这里。
谁应用代理
许多风行的库都应用了这种技术,例如:* [MobX]()
- MobX
- Vue
- Immer
还有更多 …… 他们中的大多数人都利用了 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”_属性时,咱们都会先进行计算,而后将其缓存起来。
DOM 操作
咱们想在每次余额发生变化时更新屏幕上的文字。咱们将应用一个 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 是一个很神奇的工具,你能够用它来做各种各样的抉择,你只须要想想什么最适宜你:)。
如果您喜爱这篇文章,欢送关注并拍手????。