拦截和控制与目标对象的交互
使用 Proxy 对象,我们可以更好地控制与某些对象的交互。代理对象可以在我们与对象交互时确定行为,例如,当我们获取值或设置值时。
一般来说,代理意味着其他人的替身。您无需直接与该人交谈,而是与代理人员交谈,代理人员将代表您要联系的人。在 JavaScript 中也会发生同样的情况:我们将与 Proxy 对象进行交互,而不是直接与目标对象交互。
让我们创建一个 person
对象,它代表 John Doe。
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
我们不想直接与此对象交互,而是希望与代理对象进行交互。在 JavaScript 中,我们可以通过创建一个新的 Proxy
实例来轻松创建一个新的代理。
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
const personProxy = new Proxy(person, {});
Proxy
第二个参数是表示处理程序的对象。在处理程序对象中,我们可以根据交互类型定义特定行为。尽管有许多方法可以添加到代理处理程序中,但最常见的两种方法是 get
和 set
:
get
:尝试访问属性时被调用set
:尝试修改属性时调用
代替直接使用person
对象,我们将作用于personProxy
对象。
让我们将personProxy
处理程序添加到代理。当尝试修改属性时,从而调用 上set
Proxy
的方法,我们希望代理记录属性的先前值和新值。当尝试访问属性时,从而调用Proxy
上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;
},
});
完美!让我们看看当我们尝试修改或检索属性时会发生什么。
访问 name
属性时,代理返回了一个听起来更好的句子: The value of name is John Doe
。
修改 age
属性时,代理返回此属性的上一个值和新值: Changed age from 42 to 43
。
代理可用于添加验证。用户不应能够将person
的年龄更改为字符串值,或为其指定空名称。或者,如果用户尝试访问对象上不存在的属性,我们应该让用户知道。
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;
}
},
});
让我们看看当我们尝试传递错误的值时会发生什么!
代理确保我们没有使用错误的值修改 person
对象,这有助于我们保持数据纯净!
Reflect
JavaScript 提供了一个名为 Reflect
的内置对象,这使我们在使用代理时更容易操作目标对象。
以前,我们尝试通过使用括号表示法直接获取或设置值来修改和访问代理中目标对象的属性。相反,我们可以使用该 Reflect
对象。对象上的方法与 Reflect
handler
对象上的方法同名。
我们可以通过 和 访问或修改目标对象上的属性,而不是通过 访问 obj[prop]
属性或设置属性 obj[prop] = value
。 Reflect.get()
Reflect.set()
这些方法接收与处理程序对象上的方法相同的参数。
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);
},
});
完美!我们可以使用对象 Reflect
轻松访问和修改目标对象的属性。
Tradeoffs 权衡
代理是添加对对象行为控制的强大方法。代理可以有各种用例:它可以帮助验证、格式化、通知或调试。
过度使用 Proxy
对象或对每个 handler
方法调用执行繁重的操作很容易对应用程序的性能产生负面影响。最好不要对性能关键型代码使用代理。
References 引用
- Proxy – MDN 代理 – MDN
- JavaScript Proxy – David Walsh
- Awesome ES2015 Proxy – GitHub @mikaelbr
真棒 ES2015 代理 – GitHub @mikaelbr - Thoughts on ES6 Proxies Performance – Valeri Karpov
关于 ES6 代理性能的想法 – 瓦列里·卡尔波夫
今天的文章设计模式–代理模式分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/59577.html