ECMAScript 6(18)Proxy代理 (对象的代理)
程序员文章站
2022-06-09 21:39:09
...
简述 :
- 用于修改对某个对象的属性的操作的默认行为;
- 返回值和原对象有一层代理的差异;
- 返回值还是基于原对象的一系列操作, 最终还是修改的原对象的值;
- 拦截对象的属性, 可以对其进行读取, 修改, 遍历等操作;
- 继承的属性, 拦截也有效果;
1. Proxy代理
简单说就是对对象, 加了一层中间的操作 , 你访问属性和设置属性会经过一层中间加工.
1.1 语法
var proxy = new Proxy(target, handler);
参数 :
target : 目标对象,即拦截目标,可以是原生对象或者内置对象
handler : 拦截配置,是一个对象。你对参数一拦截哪些属性,拦截后的操作如何,都是在这里配置的;
简单示例 :
var proxy = new Proxy({}, {
get: function(target, property) {
return 35;
}
});
proxy.time // 35
proxy.name // 35
2. 实例方法
就是 handler 里面可以有哪些配置
方法 | 说明 |
---|---|
get(target, propKey, receiver) | 拦截对象属性的读取,比如proxy.foo 和proxy['foo'] 。 |
set(target, propKey, value, receiver) | 拦截对象属性的设置,比如proxy.foo = v 或proxy['foo'] = v ,返回一个布尔值。 |
has(target, propKey) | 拦截propKey in proxy 的操作,返回一个布尔值。 |
deleteProperty(target, propKey) | 拦截delete proxy[propKey] 的操作,返回一个布尔值。 |
ownKeys(target) | 拦截Object.getOwnPropertyNames(proxy) 、Object.getOwnPropertySymbols(proxy) 、Object.keys(proxy) 、for...in 循 |
getOwnPropertyDescriptor(target, propKey) | 拦截Object.getOwnPropertyDescriptor(proxy, propKey) ,返回属性的描述对象。 |
defineProperty(target, propKey, propDesc) | 拦截Object.defineProperty(proxy, propKey, propDesc) 、Object.defineProperties(proxy, propDescs) ,返回一个布尔值。 |
preventExtensions(target) | 拦截Object.preventExtensions(proxy) ,返回一个布尔值。 |
getPrototypeOf(target) | 拦截Object.getPrototypeOf(proxy) ,返回一个对象。 |
isExtensible(target) | 拦截Object.isExtensible(proxy) ,返回一个布尔值。 |
setPrototypeOf(target, proto) | 拦截Object.setPrototypeOf(proxy, proto) ,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 |
apply(target, object, args) | 拦截 Proxy 实例作为函数调用的操作,比如proxy(...args) 、proxy.call(object, ...args) 、proxy.apply(...) 。 |
construct(target, args) | 拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args) 。 |
参数统一说明 :
target : 目标对象
propKey : 属性
value : 属性值
args : 参数 (数组形式)
receiver : proxy 实例本身(严格地说,是操作行为所针对的对象)(一般可省略)
下面是几个常用的方法
2.1 读取 get()
get(target, propKey, receiver)
参数 :
- 第一个参数是 目标对象
- 第二个参数是 属性
- 第三个参数是 proxy 实例本身
示例 :
var p = new Proxy(target, {
get: function(target, property, receiver) {
return target[property];
}
});
var foo = {a:1};
var bar = new Proxy(foo, {
get: function (target, key, receiver) {
return target[key];
}
});
bar.a
//1
注意 : 一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。
2.2 写入 set()
set(target, property, value, receiver)
参数 :
- 第一个参数是 目标对象
- 第二个参数是 属性
- 第三个参数是 属性值
- 第四个参数是 proxy 实例本身
示例 :
let foo = {};
let bar = new Proxy(foo, {
set(target, key, value, proxy){
if (key === 'a') {
console.log(foo === target);
console.log(key, value);
}
target.lastModify = {
key, value
}
target[key] = value;
}
})
bar.a = 1;
console.log(bar.a);
console.log(bar.lastModify);
//true
//"a" 1
//1
//{key:"a", value:"1"}
bar.b = 10;
console.log(bar.b);
console.log(bar.lastModify);
//10
//{key:"b", value:"10"}
注意 :
1. 如果目标对象自身的某个属性,不可写且不可配置,那么
set
方法将不起作用2. 严格模式下,
set
代理如果没有返回true
,就会报错。
2.3 函数拦截 apply()
每当执行proxy
函数(直接调用或call
和apply
调用),就会被apply
方法拦截。
apply (target, context, args)
参数 :
- 第一个参数是 目标对象
- 第二个参数是 目标对象的上下文对象(
this
) - 第三个参数是 目标对象的参数数组
示例 :
var twice = {
apply (target, ctx, args) {
return Reflect.apply(...arguments) * 2;
}
};
function sum (left, right) {
return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30
2.4 拦截 new 命令 construct()
construct
方法用于拦截new
命令,下面是拦截对象的写法。
construct (target, args, newTarget)
参数 :
- 第一个参数是 目标对象
- 第二个参数是 构造函数的参数对象
- 第三个参数是 创造实例对象时,
new
命令作用的构造函数
示例 :
var p = new Proxy(function () {}, {
construct: function(target, args, newTarget) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 , newTarget};
}
});
(new p(1)).value
// "called: 1"
// 10
console.log(new p().newTarget === p)
// true
更多详细的使用方法戳 阮一峰ES6
3. 可取消的 Proxy 实例 Proxy.revocable()
Proxy.revocable(target, handler);
示例 :
返回值是一个对象,他有两个属性,一个是proxy
,就是Proxy的实例,另外一个是revoke
,类型是函数,用于移除这个代理。
let target = {};
let handler = {
get(target, key){
console.log(key);
return target[key];
}
};
let obj = Proxy.revocable(target, handler);
console.log(obj); //{proxy: Proxy, revoke: function}
obj.proxy.foo = 123;
console.log(obj.proxy.foo); // 123
obj.revoke();
console.log(obj.proxy.foo); // TypeError: Revoked
Proxy.revocable
的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
4. this
上一篇: Proxy