study / 学习ES6:Proxy代理

作者 GaoGe 日期 2020-09-11
ES6
study / 学习ES6:Proxy代理

Proxy代理:由Proxy来代理某些操作。在访问目标对象时,拦截住访问并进行一系列修改的设置(用自己的定义覆盖语言的原始定义)

通过new的形式,可以创建一个proxy实例对象,写法如下:

let proxy = new Proxy(target, handler);

target参数:所要代理的的目标对象
handler参数:用来定制拦截行为的一个对象

let proxy = new Proxy({}, {
get: function(target, propKey) {
return 35;
}
});

let obj = Object.create(proxy);
obj.time // 35

上面栗子中,通过new创建出实例对象proxy,第一个参数是一个空对象(想要拦截这个空对象的访问),第二个参数是一个对象,在其内部重写get方法。

proxy作为obj对象的原型对象,当访问obj对象查找它的time属性时,obj上没有,就去它的原型对象proxy上找,调用重写的get方法得到返回值35

proxy支持多个拦截器操作,下面具体介绍:

const person = {
name: "ss",
_ID: "0000-0000"
};

let proxy = new Proxy(person, {
get: function(target, propKey) {
if (propKey in target) {
return target[propKey];
} else {
throw new ReferenceError(`${propKey} does not exist.`);
}
}

set: function(obj, prop, value) {
if (prop === 'age' && !Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
obj[prop] = value; // 满足条件直接保存
}

has (target, key) {
if (key[0] === '_') {
return false;
}
return key in target;
}

construct: function(target, args) {
return { value: args[0] * 10 };
}

deleteProperty (target, key) {
if (key[0] === '_') {
throw new Error(`private property cannot be deleted`);
}
delete target[key];
return true;
}
});

// get
proxy.name // "ss"
proxy.sex // throw Error. (如果不设拦截,此处会返回undefined)

// set
proxy.age = 100;
proxy.age = "aa"; // throw Error.

// has
'_ID' in proxy // false

// construct
(new p(1)).value // 10

// deleteProperty
delete proxy._prop // throw Error.

1. get()

get(target, propKey, receiver)

target: 目标对象
propKey:属性名
receiver:receiver指向 -> 读取这个属性或方法的那个对象(可选)

2. set()

set(target, propKey, value, receiver)

target: 目标对象
propKey:属性名
value:设置的值
receiver:receiver指向 -> 读取这个属性或方法的那个对象(一般是proxy实例本身,可选)

注意:对象设置不可写(writable: false)、不可配置( configurable: false)时,get/set 代理不生效!

3. has()

has(target, propKey):拦截propKey in proxy的操作,返回布尔值

target:目标对象
propKey:查询的属性名

注意:has方法拦截的是HasProperty操作,不是HasOwnProperty操作。即has不判断属性是对象自身的属性,还是继承来的。

4. construct()

construct(target, args):拦截new操作

target:目标对象
args:构造函数的参数对象
newTarget:创造实例对象时new作用的构造函数

5. deleteProperty()

deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回布尔值(返回false属性无法删除)。

target:目标对象
propKey:删除的属性名

6. apply()

apply(target, object, args) :函数调用,执行call,执行apply时拦截

target:目标对象
object:目标对象的上下文对象
args:参数数组

let proxy = new Proxy((left, right) => left + right, {
apply (target, ctx, args) {
return Reflect.apply(...arguments) * 2;
}
});

proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30

7. defineProperty()

defineProperty(target, propKey, propDesc):拦截Object.defineProperty,返回布尔值。

8. getOwnPropertyDescriptor()

getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor,返回属性的描述对象。

9. getPrototypeOf()

getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。