# 代理模式
TIP
拦截并控制与目标对象的交互
使用代理对象,我们可以更好地控制与某些对象的交互。当我们与代理对象交互时,代理对象可以确定行为,例如当我们获取值或设置值时。
一般来说,代理意味着其他人的替身。与其直接和那个人交谈,不如直接和代理人交谈,代理人将代表你试图联系的那个人。同样的情况也发生在 JavaScript 中: 我们不直接与目标对象交互,而是与 Proxy 对象交互。
# 例子
让我们创建一个 person 对象,它代表 John Doe。
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
我们希望与代理对象交互,而不是直接与此对象交互。在 JavaScript 中,我们可以通过创建一个新的代理实例轻松地创建一个新的代理。
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
const personProxy = new Proxy(person, {});
Proxy 的第二个参数是表示处理程序的对象。在处理程序对象中,我们可以根据交互的类型定义特定的行为。尽管有许多方法可以添加到代理处理程序中,但最常见的两个方法是 get 和 set:
- Get: 在尝试访问属性时获取调用
- Set: 在尝试修改属性时获取调用
与直接与 person 对象交互不同,我们将与 PersonProxy 交互。
让我们向 personProxy
Proxy 添加处理程序。
- 当尝试修改属性从而调用代理上的 set 方法时,我们希望代理记录属性的前一个值和新值。
- 当尝试访问一个属性,从而调用代理上的 get 方法时,我们希望代理记录一个更易读的句子,其中包含属性的键和值。
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${obj[prop]}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
obj[prop] = value;
},
});
代理对于添加验证非常有用。用户不应该将人的年龄改为字符串值,或者给他们一个空名称。或者,如果用户试图访问对象上不存在的属性,我们应该让用户知道。
const personProxy = new Proxy(person, {
get: (obj, prop) => {
if (!obj[prop]) {
console.log(
`Hmm.. this property doesn't seem to exist on the target object`
);
} else {
console.log(`The value of ${prop} is ${obj[prop]}`);
}
},
set: (obj, prop, value) => {
if (prop === "age" && typeof value !== "number") {
console.log(`Sorry, you can only pass numeric values for age.`);
} else if (prop === "name" && value.length < 2) {
console.log(`You need to provide a valid name.`);
} else {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}.`);
obj[prop] = value;
}
},
});
代理确保我们没有用错误的值修改人对象,这有助于我们保持数据的纯粹性!
# 反射
JavaScript 提供了一个内置的对象,名为 Refect,这使得我们在使用代理时更容易操作目标对象。
以前,我们试图通过直接获取或设置带括号符号的值来修改和访问代理中目标对象的属性。相反,我们可以使用反射对象。反射对象上的方法与处理程序对象上的方法具有相同的名称。
我们可以通过 Refect.get ()和 Refect.set ()访问或修改目标对象上的属性,而不是通过 obj [ prop ]访问属性或通过 obj [ prop ] = value 设置属性。这些方法接收的参数与处理程序对象上的方法相同。
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${Reflect.get(obj, prop)}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
Reflect.set(obj, prop, value);
},
});
# 取舍
代理是增加对对象行为控制的强大方法。代理可以有各种用例: 它可以帮助进行验证、格式化、通知或调试。
过度使用代理对象或对每个处理程序方法调用执行大量操作很容易对应用程序的性能产生负面影响。对于性能关键型代码,最好不要使用代理。