文章目录
前言
此系列文章用于记录小萌新的ES6的学习经历如有什么错误或者不好的地方请各位大佬多多指教
一、代理器基本概念
- 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
- Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
ES6提供了原生的Proxy的构造方法,用来创建Proxy的实例:
代码如下(示例):
{
let obj = new Proxy(
{},
{
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}`);
return Reflect.set(target, propKey, value, receiver);
},
}
);
obj.count = 1;
++obj.count;
console.log(obj);
}
输出为:
setting count
getting count
setting count
{ count: 2 }
可以看到Proxy代理种的参数主要包括两个,这里有一个空对象和一个包含了各种拉杰操作的处理对象,而在外面调用响应的拦截操作就会出发对该obj对象的操作方法进行拦截并进行处理。具体方法和操作请看下面。
二、代理器的基本使用
2.1.创建代理器
new Proxy(target, handler)
new Proxy()表示生成一个Proxy实例。
target参数表示所要拦截的目标对象。
handler参数也是一个对象,用来定制拦截行为。
示例:拦截一个读取操作
代码如下(示例):
{
let proxy = new Proxy(
{},
{
get(target, propKey) {
return 35;
},
}
);
console.log(proxy.time); // 35
console.log(proxy.name); // 35
console.log(proxy.title); // 35
}
- 在每一次读取
proxy
实例对象的时候都会出发get
拦截操作不管你读取的是什么属性在拦截后都只会返回35. - 如果在代理器对象种的handler没有进行任何的拦截则所有操作都会直接传到源对象。
2.2.Proxy 对象设置到object.proxy属性
把Proxy对象设置到属性中,可以在使用对象的时候进行选择性的是否使用代理器。
代码如下(示例):
{
let obj = {
proxy: new Proxy(this, {
get(target, prop) {
console.log(`getting ${prop}`);
return target[prop] ?? "Not Found";
},
}),
};
let x1 = obj.proxy.a;
let x2 = obj.a;
console.log(x); // Not Found
console.log(x); // undefined
}
把proxy
当作属性存在对象中则可以选择性的是否使用代理器进行对对象的一切处理。(如读取、设置属性、创建实例等操作进行拦截)
三、代理器中的拦截器对象
3.1.拦截器的多种拦截操作
在拦截器中可以对对象的基本上一切的操作进行拦截处理。
代码如下(示例):
{
let handler = {
get(target, name) {
if (name == "prototype") {
return Object.prototype;
}
return `Hello, ${name}`;
},
apply(target, thisBinding, args) {
return args[0];
},
construct(target, args) {
let obj = new target(...args);
obj.name = "foo";
obj.value = args[1];
return obj;
},
};
let fproxy = new Proxy(function (x, y) {
return x + y;
}, handler);
console.log(fproxy(1, 2)); // 1
console.log(new fproxy(1, 2)); // { name: 'foo', value: 2 }
console.log(fproxy.prototype === Object.prototype); // true
console.log(fproxy.foo); //Hello, foo
}
- 可以看到在第一个输出中,我们使用了
apply
方法对求和方法进行了调用拦截最后输出的只有传入参数的第一个。 - 在第二个输出中使用了
construct
方法对该方法的创建实例对象进行了拦截所以输出了我们经过处理的一些信息。 - 在获取
fproxy
中的foo
属性的时候出发了get
方法对对象的属性读取操作进行了拦截并进行了处理。
3.2.Proxy所支持的拦截操作
在下列拦截操作中比较常用的就是get(属性的读取)
、set(属性的设置)
、apply(作为函数调用的时候)
、construct(拦截实例作为构造函数的时候)
具体的使用方法可以去mdn上看一下全部的api:ProxyAPI.
方法 | 描述 |
---|---|
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) |
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)。 |
总结
本文主要讲述了ES6中的代理器方面的知识,如果又不好的地方希望大家多多提意见。