📅  最后修改于: 2023-12-03 15:16:10.010000             🧑  作者: Mango
代理是在大多数编程语言中都存在的重要机制,JavaScript 也不例外。JavaScript 通过代理可以控制对象的访问和修改,从而实现更加灵活和强大的功能。
代理是通过 Proxy
对象来创建的,创建一个代理对象需要传入两个参数:需要代理的对象和一个控制代理行为的 handler
对象。
const target = {};
const handler = {};
const proxy = new Proxy(target, handler);
上面的代码创建了一个代理对象 proxy
,它可以控制对目标对象 target
的访问和修改行为。
handler
对象包含了一系列的属性,用来指定对代理对象的不同操作的行为。下面是一些常用的属性:
get
属性用来控制对代理对象属性的访问行为,当访问代理对象属性时,get
方法会被调用。
const target = {
name: 'Tom'
};
const handler = {
get(target, key) {
console.log(`get property ${key}`);
return target[key];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 'Tom'
上面的代码定义了一个 get
方法,它在访问代理对象属性时会打印一条日志。当我们访问代理对象的 name
属性时,会先调用 get
方法打印日志,然后返回目标对象的 name
属性值。
set
属性用来控制对代理对象属性的赋值行为,当给代理对象属性赋值时,set
方法会被调用。
const target = {};
const handler = {
set(target, key, value) {
console.log(`set property ${key} to ${value}`);
target[key] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
proxy.name = 'Tom'; // 'set property name to Tom'
上面的代码定义了一个 set
方法,它在给代理对象赋值时会打印一条日志。当我们给代理对象的 name
属性赋值时,会先调用 set
方法打印日志,然后将值赋给目标对象的 name
属性。
has
属性用来控制对代理对象属性的in
操作符行为,当使用in
操作符检查代理对象属性存在性时,has
方法会被调用。
const target = {
name: 'Tom'
};
const handler = {
has(target, key) {
console.log(`has property ${key}`);
return key in target;
}
};
const proxy = new Proxy(target, handler);
console.log('name' in proxy); // 'has property name', true
上面的代码定义了一个 has
方法,它在检查代理对象属性存在性时会打印一条日志。当我们使用 in
操作符检查代理对象的 name
属性存在性时,会先调用 has
方法打印日志,然后返回 true
。
deleteProperty
属性用来控制对代理对象属性的删除行为,当删除代理对象属性时,deleteProperty
方法会被调用。
const target = {
name: 'Tom'
};
const handler = {
deleteProperty(target, key) {
console.log(`delete property ${key}`);
delete target[key];
return true;
}
};
const proxy = new Proxy(target, handler);
delete proxy.name; // 'delete property name'
上面的代码定义了一个 deleteProperty
方法,它在删除代理对象属性时会打印一条日志。当我们删除代理对象的 name
属性时,会先调用 deleteProperty
方法打印日志,然后删除目标对象的 name
属性。
除了上面介绍的基本操作外,代理还可以实现一些高级功能。
代理对象可以嵌套,就是说一个代理对象可以作为另一个代理对象的目标对象。这使得我们可以通过串联多个代理对象来实现更加灵活和强大的功能。
const target = {};
const handler1 = {
get(target, key) {
console.log(`get property ${key}`);
return target[key];
}
};
const handler2 = {
set(target, key, value) {
console.log(`set property ${key} to ${value}`);
target[key] = value;
return true;
}
};
const proxy1 = new Proxy(target, handler1);
const proxy2 = new Proxy(proxy1, handler2);
proxy2.name = 'Tom'; // 'set property name to Tom'
console.log(proxy2.name); // 'get property name', 'Tom'
上面的代码创建了两个代理对象 proxy1
和 proxy2
,它们分别对目标对象 target
进行代理。其中,proxy1
只是在访问目标对象属性时打印一条日志,而 proxy2
既能够在赋值时打印日志,同时又能够访问目标对象属性。
除了直接调用 get
、set
等方法之外,我们还可以通过反射 API 来操作代理对象。反射 API 是一组静态方法,用来直接调用各种代理行为。
const target = {
name: 'Tom'
};
const handler = {
get(target, key) {
console.log(`get property ${key}`);
return target[key];
}
};
const proxy = new Proxy(target, handler);
console.log(Reflect.get(proxy, 'name')); // 'get property name', 'Tom'
上面的代码使用 Reflect.get
方法来访问代理对象的 name
属性。Reflect.get
方法会先查找代理对象中是否有 get
方法,如果有则调用之,否则会直接返回目标对象对应属性的值。
代理是 JavaScript 中非常有用的一种机制,能够极大地增强对象的控制能力。使用代理,我们可以控制对象的访问和修改行为,实现更加灵活和强大的功能。同时,代理也有一些高级的用法,如代理嵌套和反射 API 等,能够进一步扩展代理的功能。