JavaScript代理

发布于:2021-01-24 00:00:57

0

87

0

JavaScript 代理

我一直都很喜欢JavaScript中对象和原型的灵活性,但很长一段时间以来,我觉得缺乏一定程度的动态性。JavaScript最终为对象属性添加了get和set方法,这是一个很棒的步骤,但仍然有改进的空间。

JavaScript代理API是一个令人敬畏的改进:一个控制对象修改行为的虚拟化接口!

代理的格式

代理接受一个要代理的对象,以及一个带有get、set、has和其他常见对象方法处理程序(“陷阱”)的对象:

const proxy = new Proxy({}, {   get: (obj, prop) => { ... },   set: (obj, prop, value) => { ... },   // more props here });

任何设置或获取属性的尝试都将通过该陷阱运行,从而允许您运行额外的逻辑,特别是当该属性不需要、不存在或需要验证时。

基本用法

让我们创建一个基本的代理,为任何给定的属性返回默认值:

const proxy = new Proxy({}, {   get: (obj, prop) => {     return prop in obj ? obj[prop] : null;   } }); // proxy.whatever => null

上面的示例说明了,无论代码试图设置什么属性,您的代理逻辑都可以根据需要捕获并修改它。对于不存在的属性,可以返回null,而不是undefined。

验证

代理最明显和最有用的用法是验证;由于您可以监视并验证传入的任何属性,所以可以尽可能地保持数据的纯粹性。

const proxy = new Proxy({}, {    set: (obj, prop, value) => {     // Don't allow age > 100     if (prop === "age" && value > 100) {       // Set to max age       value = 100;     }     obj[prop] = value;   } }); proxy.age = 120; proxy.age; // 100

你可以选择像上面的例子那样修改传入的数据,或者你可以抛出一个错误:

const proxy = new Proxy({}, {    set: (obj, prop, value) => {     // Ensure age is of type Number     if (prop === "age" && isNaN(value)) {       throw new Error("Invalid age value!");       return;     }     obj[prop] = value;   } }); proxy.age = "yes";  // Uncaught error: Invalid age value!

调试

你甚至可以使用Proxy来为自己提供调试点或事件,以查看如何以及何时设置和获取值:

const proxy = new Proxy({}, {    set: (obj, prop, value) => {     console.log(`Setting ${prop} from ${obj[prop]} to ${value}`);     obj[prop] = value;   } }); proxy.prop = 1; proxy.prop = 2; // Setting prop from undefined to 1 // Setting prop from 1 to 2

即使您不修改任何输入或输出,拥有一个对象上值更改的挂钩也是非常有价值的。

格式化

另一个简单的用法是格式化进入对象的数据:

const proxy = new Proxy({}, {    set: (obj, prop, value) => {     if (prop === "age") {       obj[prop] = Number(value);     }   } }); proxy.prop = "1"; // 1

您可以格式化字符串到数字,数字到字符串,或简单地设置默认值。

使用现有对象的代理

在上面的例子中,我们使用了空对象({}),但你也可以使用现有的对象:

const myObj = { x: "x", y: "y" }; // Use existing object, simply set value as is given const proxy = new Proxy(myObj, {    set: (obj, prop, value) => {      obj[prop] = value;    }  }); //  proxy.x = "XXX"; proxy.x; // "XXX" myObj.x; // "XXX"

请注意,原始对象和代理都会发生变化,因此代理不能充当“副本”。

人们讨厌PHP,但我喜欢这门语言的一点是你可以监视和动态响应的“魔法属性”。代理API感觉像是JavaScript对这个问题的回答。你能控制的东西越多,你的应用就会变得越好!