什么是代理?
代理类,用来进行事物不想或不能进行的其他操作,比如当你对数据库进行操作时,代理可以在你对数据库操作完后,记录下你所进行的操作。
Proxy对象可以让你为另一个对象创建一个代理,它可以拦截和重新定义该对象的基本操作。
基本上,它的意思是说,我们要把一个对象,用Proxy包裹起来,这将允许我们创建一个 "隐藏 "的门,并控制所有对所需对象的访问。
一个Proxy的创建有两个参数。
target: 你想包裹的原始对象(proxy)
handler:定义哪些操作将被拦截,以及如何重新定义被拦截的操作的对象,也可以调用 “陷阱”。
const target = {
message1: "hello",
message2: "everyone"
};
const handler = {};
const proxt = new Proxy(target, handler)
大多数浏览器都支持代理功能,但也有一些老的浏览器不支持(当然是IE),你可以在这里查看完整的列表。google有一个代理的polyfill,但它不支持所有的代理功能。
现在知道了什么是Proxies,想看看能用它做什么。
现在假设有一个银行账号,有名字和余额属性,每次放问余额时我们想知道被访问的时间。
const bankAccount = {
balance: 2021,
name: 'feng'
}
const handler = {
get: function (target, prop) {
if (prop === 'balance') {
console.log(`当前余额: ${target.balance}`)
}
return target[prop]
}
}
const bankProxy = new Proxy(bankAccount, handler)
bankProxy.balance // 当前余额2021
在上面的例子中,我们有一个银行账户对象,里面有我的名字和2021的余额。
这次的处理者对象是实现get操作/trap,它接收一个有2个参数的函数和get的返回值。
- target: 被访问的对象(我们封装的对象)。
- prop:被访问的对象(我们封装的对象)。在我们的例子中被访问的属性,这里是 “balance”。
我们定义了一个条件,如果被访问的属性是 “余额”,我们将通知(log)余额和当前用户名,并返回 "余额 "属性。
从输出中可以看到,一旦 "balance "属性被访问,我们就通过使用Proxy和设置get操作/陷阱,很容易地通知(log)了这次访问。
继续我们银行的想法,要求每次有人从银行账户中取钱,我们都要得到通知。而另一个约束条件是,银行不允许出现负余额。为了达到这个目的,我们这次要使用设置处理程序/陷阱。
const bankAccount = {
balance: 2021,
name: 'feng'
}
const handler = {
set: function (target, prop, value) {
if (prop === 'balance') {
if (value < 0) {
console.log('余额低于取出金额')
return false
}
target[prop] = value
console.log(`已取出${value}`)
return true
}
}
}
const bankProxy = new Proxy(bankAccount, handler)
bankProxy.balance -= 2000 // 取出2000
bankProxy.balance -= 22 // 余额低于取出金额
在上面的例子中,我们通知当前的余额和取款后的新余额,如果新的余额是负数,我们也会通知并中止取款操作。
我们使用的是set operator/trap,它是一个返回布尔值(true/false)的函数,用来判断更新操作是否成功。它接收以下参数。
- target: 被访问的对象(我们封装的对象)。
- prop.prop:被访问的对象(我们封装的对象)。在我们的例子中,被访问的属性是 “balance”。
值。应该更新的新值。 - value: 接收器。赋值最初指向的对象。这通常是代理本身。但是set()处理程序也可以间接调用,通过原型链或其他各种方式
你可以看到,它和get真的很相似,但只是多接收了1个新值的参数
Dom操作
我们想在每次余额发生变化时更新屏幕上的文字。我们将使用一个set操作符/trap,每次改变数值时,我们将更新屏幕上的DOM元素。
const bankAccount = {
balance: 2020,
name: "feng",
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元素。很简单,对吧?让我们看看结果:)