proxy-pattern
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProxy Pattern
Proxy 模式
With a Proxy object, we get more control over the interactions with certain objects. A proxy object can determine the behavior whenever we're interacting with the object, for example when we're getting a value, or setting a value.
借助Proxy对象,我们可以更精准地控制与特定对象的交互。当我们与对象进行交互时(比如获取值或设置值),代理对象可以决定具体的行为。
When to Use
适用场景
- Use this when you need to add validation, formatting, notifications, or debugging to object access
- This is helpful for controlling and intercepting property gets and sets on objects
- 当你需要为对象访问添加验证、格式化、通知或调试功能时,可以使用该模式
- 它有助于控制和拦截对象属性的获取与设置操作
Instructions
使用说明
- Create a with a handler object defining
Proxyandgettrapsset - Use the object within handlers for cleaner property access and modification
Reflect - Add validation logic in the trap to ensure data integrity
set - Avoid using proxies in performance-critical code paths as they add overhead
- 创建一个带有处理程序对象的,该对象定义
Proxy和get捕获器set - 在处理程序中使用对象,以更简洁地进行属性访问和修改
Reflect - 在捕获器中添加验证逻辑,确保数据完整性
set - 避免在性能敏感的代码路径中使用代理,因为它们会带来额外开销
Details
详细说明
Generally speaking, a proxy means a stand-in for someone else. Instead of speaking to that person directly, you'll speak to the proxy person who will represent the person you were trying to reach. The same happens in JavaScript: instead of interacting with the target object directly, we'll interact with the Proxy object.
Let's create a object, that represents John Doe.
personjs
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};Instead of interacting with this object directly, we want to interact with a proxy object. In JavaScript, we can easily create a new proxy by creating a new instance of .
Proxyjs
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
const personProxy = new Proxy(person, {});The second argument of is an object that represents the handler. In the handler object, we can define specific behavior based on the type of interaction. Although there are many methods that you can add to the Proxy handler, the two most common ones are and :
Proxygetset- : Gets invoked when trying to access a property
get - : Gets invoked when trying to modify a property
set
Instead of interacting with the object directly, we'll be interacting with the .
personpersonProxyLet's add handlers to the Proxy. When trying to modify a property, thus invoking the method on the , we want the proxy to log the previous value and the new value of the property. When trying to access a property, thus invoking the method on the , we want the proxy to log a more readable sentence that contains the key and value of the property.
personProxysetProxygetProxyjs
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;
},
});When accessing the property, the Proxy returned a better sounding sentence: .
nameThe value of name is John DoeWhen modifying the property, the Proxy returned the previous and new value of this property: .
ageChanged age from 42 to 43A proxy can be useful to add validation. A user shouldn't be able to change 's age to a string value, or give them an empty name. Or if the user is trying to access a property on the object that doesn't exist, we should let the user know.
personjs
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;
}
},
});The proxy makes sure that we aren't modifying the object with faulty values, which helps us keep our data pure!
person一般来说,代理指的是他人的替身。你不会直接与本人沟通,而是与代表对方的代理进行交流。JavaScript中的代理也是如此:我们不会直接与目标对象交互,而是与Proxy对象交互。
让我们创建一个代表John Doe的对象。
personjs
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};我们不希望直接与这个对象交互,而是通过代理对象进行操作。在JavaScript中,我们可以通过创建的新实例轻松生成一个新代理。
Proxyjs
const person = {
name: "John Doe",
age: 42,
nationality: "American",
};
const personProxy = new Proxy(person, {});- :当尝试访问属性时触发
get - :当尝试修改属性时触发
set
我们将不再直接与对象交互,而是与交互。
personpersonProxy让我们为代理添加处理程序。当尝试修改属性(即触发Proxy的方法)时,我们希望代理记录该属性的旧值和新值。当尝试访问属性(即触发Proxy的方法)时,我们希望代理输出一句更易读的语句,包含属性的键和值。
personProxysetgetjs
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;
},
});当访问属性时,代理会返回一句更友好的语句:。
nameThe value of name is John Doe当修改属性时,代理会返回该属性的旧值和新值:。
ageChanged age from 42 to 43代理可用于添加验证功能。用户不能将的年龄修改为字符串值,也不能设置空名称。如果用户尝试访问对象上不存在的属性,我们应该提示用户。
personjs
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;
}
},
});代理确保我们不会用错误的值修改对象,这有助于保持数据的纯净性!
personReflect
ReflectReflect
对象
ReflectJavaScript provides a built-in object called , which makes it easier for us to manipulate the target object when working with proxies.
ReflectPreviously, we tried to modify and access properties on the target object within the proxy through directly getting or setting the values with bracket notation. Instead, we can use the object. The methods on the object have the same name as the methods on the object.
ReflectReflecthandlerInstead of accessing properties through or setting properties through , we can access or modify properties on the target object through and . The methods receive the same arguments as the methods on the handler object.
obj[prop]obj[prop] = valueReflect.get()Reflect.set()js
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);
},
});We can access and modify the properties on the target object easily with the object.
ReflectJavaScript提供了一个名为的内置对象,它让我们在使用代理时更轻松地操作目标对象。
Reflect之前,我们在代理中通过方括号表示法直接获取或设置值来操作目标对象的属性。现在,我们可以使用对象。对象上的方法与处理程序对象上的方法名称相同。
ReflectReflect我们不再通过访问属性或设置属性,而是可以通过和来访问或修改目标对象的属性。这些方法接收的参数与处理程序对象上的方法相同。
obj[prop]obj[prop] = valueReflect.get()Reflect.set()js
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);
},
});借助对象,我们可以轻松地访问和修改目标对象的属性。
ReflectTradeoffs
权衡利弊
Proxies are a powerful way to add control over the behavior of an object. A proxy can have various use-cases: it can help with validation, formatting, notifications, or debugging.
Overusing the object or performing heavy operations on each method invocation can easily affect the performance of your application negatively. It's best to not use proxies for performance-critical code.
Proxyhandler代理是一种强大的方式,可用于控制对象的行为。代理有多种应用场景:它可以帮助实现验证、格式化、通知或调试功能。
过度使用对象或在每次调用处理程序方法时执行繁重操作,很容易对应用程序性能产生负面影响。最好不要在性能敏感的代码中使用代理。
ProxySource
来源
References
参考资料
- Proxy - MDN
- JavaScript Proxy - David Walsh
- Awesome ES2015 Proxy - GitHub @mikaelbr
- Thoughts on ES6 Proxies Performance - Valeri Karpov
- Proxy - MDN
- JavaScript Proxy - David Walsh
- Awesome ES2015 Proxy - GitHub @mikaelbr
- Thoughts on ES6 Proxies Performance - Valeri Karpov