代理
ES6(ECMAScript 2015)引入的Proxy对象允许你创建一个代理对象,它可以作为访问目标对象的中介。通过Proxy,你可以拦截并自定义基本操作的行为,如属性查找、赋值、枚举、函数调用等。这为开发者提供了强大的能力来扩展对象的行为,实现诸如数据验证、日志记录、私有属性等功能。
创建 Proxy
要创建一个代理,你需要使用Proxy构造函数,并传入两个参数:目标对象(target)和处理器对象(handler)。处理器对象包含了一些方法,这些方法对应着可以被拦截的操作。
javascript
let target = {};
let handler = {
get: function (obj, prop) {
return prop in obj ? obj[prop] : 37;
},
};
let proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出: 37
target.name = "Alice";
console.log(proxy.name); // 输出: Alice在这个例子中,如果尝试访问proxy对象上不存在的属性,则返回默认值37。
常见的处理器方法
get()
拦截对对象属性的读取操作。
javascript
let handlerGet = {
get: function (obj, prop, receiver) {
console.log(`Getting ${prop}`);
return Reflect.get(...arguments);
},
};
let proxyGet = new Proxy({ name: "Alice" }, handlerGet);
console.log(proxyGet.name); // 控制台输出: Getting name \n Aliceset()
拦截对对象属性的设置操作。
javascript
let handlerSet = {
set: function (obj, prop, value, receiver) {
if (typeof value === "string") {
return Reflect.set(obj, prop, value.toUpperCase(), receiver);
} else {
return Reflect.set(...arguments);
}
},
};
let proxySet = new Proxy({}, handlerSet);
proxySet.name = "Alice";
console.log(proxySet.name); // 输出: ALICEhas()
拦截in操作符。
javascript
let handlerHas = {
has: function (obj, prop) {
if (prop == "secret") return false;
return prop in obj;
},
};
let proxyHas = new Proxy({ name: "Alice", secret: "hidden" }, handlerHas);
console.log("name" in proxyHas); // 输出: true
console.log("secret" in proxyHas); // 输出: falsedeleteProperty()
拦截delete操作。
javascript
let handlerDelete = {
deleteProperty: function (obj, prop) {
console.log(`Deleting ${prop}`);
return Reflect.deleteProperty(...arguments);
},
};
let proxyDelete = new Proxy({ name: "Alice" }, handlerDelete);
delete proxyDelete.name; // 控制台输出: Deleting name
console.log("name" in proxyDelete); // 输出: false应用场景
- 数据验证:可以在设置属性值之前进行数据验证。
- 日志记录:在获取或设置属性值时记录日志信息。
- 私有属性:通过代理隐藏某些属性,使其对外不可见。
- 依赖追踪:用于观察对象的变化,在响应式系统中非常有用,比如 Vue.js 中的反应性系统。
结合Reflect使用
Proxy通常与Reflect一起使用,以执行默认行为。例如,在处理set操作时,可以通过Reflect.set()确保属性能够正常设置。
javascript
let target = { name: "Alice" };
let handler = {
set: function (obj, prop, value, receiver) {
if (value.length > 2) {
return Reflect.set(obj, prop, value, receiver);
} else {
console.log("Too short");
return false; // 表示设置失败
}
},
};
let proxy = new Proxy(target, handler);
proxy.name = "Jo"; // 控制台输出: Too short
proxy.name = "John";
console.log(proxy.name); // 输出: John通过Proxy,JavaScript 提供了一种灵活且强大的方式来定制对象的基本操作,极大地增强了代码的可扩展性和维护性。