代理基础
代理是es6为开发者提供的可以拦截住针对对象的一些底层操作,并且额外在这基础上面添加一些其他的行为。 它相当于一个看门的,拦住来客(底层操作)问话(开发者逻辑)。行就开门进去,不行就打一顿丢出去
创建代理
const handler = {}
const target = {
id: 'target'
}
const proxy = new Proxy(target, handler)
代理是由Proxy构造函数创建出来的一个代理对象,构造函数接收两个参数
- target 目标对象(要操作的对象)
- handler 处理程序对象(拦截后触发的捕获器api的集合对象)
目标对象可以直接调用,我们也可以通过代理对象进行调用。最终的操作结果也会反映到目标对象里面
const handler = {}
const target = {
id: 'target'
}
const proxy = new Proxy(target, handler)
proxy.id = 'proxy'
// 修改代理对象的属性值,也会反映到目标对象
console.log(target) // { id: "proxy" }
console.log(proxy) // { id: 'proxy' }
// 再目标对象里面操作,同样也会反映到代理对象
// 因为引用的是同一个对象
traget.name = 'yu'
console.log(target) // { id: "proxy", name: 'yu' }
console.log(proxy) // { id: "proxy", name: 'yu' }
注:Proxy构造函数的prototype是undefined
捕获器
代理之所以能够针对底层操作进行拦截并且能够进行额外的操作,就是通过捕获器来实现的。捕获器是定义再处理程序对象里面的,一个处理程序对象可以定义多个捕获器方法。每个捕获器都对应着一个基本操作。
- 比如获取对象属性的操作,对应着get捕获器方法
const handler = {
get(target, property, proxy) {
console.log('触发了get方法')
return target[property]
}
}
const target = {
id: 'target'
}
const proxy = new Proxy(target, handler)
proxy.id // '触发了get方法'
这些捕获器只在代理对象触发,直接使用目标对象是不会触发的
捕获器方法都有对应的参数,通过这些参数可以重新构建新的行为逻辑。比如get方法就会有三个参数
- target 目标对象
- property 要查询的属性
- proxy 代理对象
一个代理里面包含着13种捕获器方法,这些捕获器方法可以重新构造新的行为。但是也要遵守一个就是要有这个操作的原始行为,但是有些原始行为十分复制,我们手动如法炮制可能很麻烦。所以es6给开发者提供了反射API,他给我们提供了基本的原始行为不需要我们来写。
反射(Reflect)
反射对象是一个有13个方法的对象,相当于一个Object的子集。但是它将Object的一些命令式的操作转变成了函数式。
- 比如 in操作符 这个就对应着Reflect.has
- 比如 delete操作符 这个就对应着Reflect.deleteProperty
反射对象还有一个好处就是修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false
reflect对象的最大作用是和proxy代理对象的捕获器的方法是一一对应的,可以结合proxy代理对象一起使用
const target = {
id: 'target'
}
const handler = {
get(target, property, handler) {
let a = ''
if (property === 'id') {
a = '!!!'
}
return Reflect.get(...arguments) + a
}
}
const proxy = new Proxy(target, handler)
console.log(proxy.id) // target!!!
捕获器API
get()
get捕获器是再获取属性的时候触发的,对应的反射api是Reflect.get
get方法的返回值是没有限制的
拦截的操作
- proxy.property
- proxy[property]
- Object.create(proxy)[property]
- Reflect.get(proxy, property, receiver)
参数
- target 目标对象
- property 要查询的属性
- proxy 代理对象
const myTarget = {};
const proxy = new Proxy(myTarget, {
get(target, property, receiver) {
console.log('get()');
return Reflect.get(...arguments)
}
});
proxy.foo;
// get()
set()
set捕获器是通过设置属性的时候触发的,对应的反射api是Reflect.set
set方法的返回值 返回 true 表示成功;返回 false 表示失败,严格模式下会抛出 TypeError
拦截操作
- proxy.property = value
- proxy[property] = value
- Object.create(proxy)[property] = value
- Reflect.set(proxy, property, value, receiver)
参数
- target:目标对象。
- property:引用的目标对象上的字符串键属性。
- value:要赋给属性的值。
- receiver:接收最初赋值的对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
set(target, property, value, receiver) {
console.log('set()');
return Reflect.set(...arguments)
}
});
proxy.foo = 'bar';
// set()
has()
has捕获器是通过使用了in操作符触发的,对应的反射api是Reflect.has()
has方法必须返回布尔值,表示属性是否存在。返回非布尔值会被转型为布尔值
拦截操作
- property in proxy
- property in Object.create(proxy)
- with(proxy) {(property);}
- Reflect.has(proxy, property)
参数
- target:目标对象。
- property:引用的目标对象上的字符串键属性。
const myTarget = {};
const proxy = new Proxy(myTarget, {
has(target, property) {
console.log('has()');
return Reflect.has(...arguments)
}
});
'foo' in proxy;
// has()
defineProperty()
defineProperty捕获器是通过使用了Object.defineProperty()中被触发,对应的反射api是Reflect.defineProperty()
defineProperty方法必须返回布尔值,表示属性是否成功定义。返回非布尔值会被转型为布尔值。
拦截操作
- Object.defineProperty(proxy, property, descriptor)
- Reflect.defineProperty(proxy, property, descriptor)
参数
- target:目标对象。
- property:引用的目标对象上的字符串键属性。
- descriptor:包含可选的 enumerable、configurable、writable、value、get 和 set定义的对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
defineProperty(target, property, descriptor) {
console.log('defineProperty()');
return Reflect.defineProperty(...arguments)
}
});
Object.defineProperty(proxy, 'foo', { value: 'bar' });
// defineProperty()
getOwnPropertyDescriptor()
getOwnPropertyDescriptor捕获器是通过使用了Object.getOwnPropertyDescriptor()中触发的,对应的反射api是Reflect.getOwnPropertyDescriptor()
getOwnPropertyDescriptor方法必须返回对象,或者在属性不存在时返回 undefined。
拦截操作
- Object.getOwnPropertyDescriptor(proxy, property)
- Reflect.getOwnPropertyDescriptor(proxy, property)
参数
- target:目标对象。
- property:引用的目标对象上的字符串键属性。
const myTarget = {};
const proxy = new Proxy(myTarget, {
getOwnPropertyDescriptor(target, property) {
console.log('getOwnPropertyDescriptor()');
return Reflect.getOwnPropertyDescriptor(...arguments)
}
});
Object.getOwnPropertyDescriptor(proxy, 'foo');
// getOwnPropertyDescriptor()
deleteProperty()
deleteProperty捕获器是通过使用了delete操作符触发的,对应的反射api是Reflect.deleteProperty()
deleteProperty方法必须返回布尔值,表示删除属性是否成功。返回非布尔值会被转型为布尔值。
拦截操作
- delete proxy.property
- delete proxy[property]
- Reflect.deleteProperty(proxy, property)
参数
- target:目标对象。
- property:引用的目标对象上的字符串键属性。
const myTarget = {};
const proxy = new Proxy(myTarget, {
deleteProperty(target, property) {
console.log('deleteProperty()');
return Reflect.deleteProperty(...arguments)
}
});
delete proxy.foo
// deleteProperty()
ownKeys()
ownKeys捕获器是通过Object.keys()及类似方法中被触发。对应的反射 API 方法为 Reflect.ownKeys()
拦截操作
- Object.getOwnPropertyNames(proxy)
- Object.getOwnPropertySymbols(proxy)
- Object.keys(proxy)
- Reflect.ownKeys(proxy)
参数
- target:目标对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
ownKeys(target) {
console.log('ownKeys()');
return Reflect.ownKeys(...arguments)
}
});
Object.keys(proxy);
// ownKeys()
getPrototypeOf()
getPrototypeOf捕获器是通过在 Object.getPrototypeOf()获取原型对象中被触发的,对应的Reflect.getPrototypeOf()
getPrototypeOf()必须返回对象或 null。
拦截操作
- Object.getPrototypeOf(proxy)
- Reflect.getPrototypeOf(proxy)
- proxy.proto
- Object.prototype.isPrototypeOf(proxy)
- proxy instanceof Object
参数
- target:目标对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
getPrototypeOf(target) {
console.log('getPrototypeOf()');
return Reflect.getPrototypeOf(...arguments)
}
});
Object.getPrototypeOf(proxy);
// getPrototypeOf()
setPrototypeOf()
setPrototypeOf捕获器是通过使用Object.setPrototypeOf()设置原型对象中触发的,对应的Reflect.setPrototypeOf()
setPrototypeOf方法必须返回布尔值,表示原型赋值是否成功。返回非布尔值会被转型为布尔值
拦截操作
- Object.setPrototypeOf(proxy)
- Reflect.setPrototypeOf(proxy)
参数
- target:目标对象。
- prototype:target 的替代原型,如果是顶级原型则为 null。
const myTarget = {};
const proxy = new Proxy(myTarget, {
setPrototypeOf(target, prototype) {
console.log('setPrototypeOf()');
return Reflect.setPrototypeOf(...arguments)
}
});
Object.setPrototypeOf(proxy, Object);
// setPrototypeOf()
isExtensible
isExtensible捕获器的通过Object.isExtensible()是否可扩展中被调用。对应的反射 API 方法为Reflect.isExtensible()
isExtensible()必须返回布尔值,表示 target 是否可扩展。返回非布尔值会被转型为布尔值。
拦截操作
- Object.isExtensible(proxy)
- Reflect.isExtensible(proxy)
参数
- target:目标对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
isExtensible(target) {
console.log('isExtensible()');
return Reflect.isExtensible(...arguments)
}
});
Object.isExtensible(proxy);
// isExtensible()
preventExtensions
preventExtensions捕获器会在 Object.preventExtensions()中被调用。对应的反射 API方法为 Reflect.preventExtensions()。
preventExtensions()必须返回布尔值,表示 target 是否已经不可扩展。返回非布尔值会被转型为布尔值
拦截操作
- Object.preventExtensions(proxy)
- Reflect.preventExtensions(proxy)
参数
- target:目标对象。
const myTarget = {};
const proxy = new Proxy(myTarget, {
preventExtensions(target) {
console.log('preventExtensions()');
return Reflect.preventExtensions(...arguments)
}
});
Object.preventExtensions(proxy);
// preventExtensions()
apply
apply捕获器会在调用函数时中被调用。对应的反射 API 方法为 Reflect.apply()
拦截操作
- proxy(...argumentsList)
- Function.prototype.apply(thisArg, argumentsList)
- Function.prototype.call(thisArg, ...argumentsList)
- Reflect.apply(target, thisArgument, argumentsList)
参数
- target:目标对象。
- thisArg:调用函数时的 this 参数。
- argumentsList:调用函数时的参数列表
const myTarget = () => {};
const proxy = new Proxy(myTarget, {
apply(target, thisArg, ...argumentsList) {
console.log('apply()');
return Reflect.apply(...arguments)
}
});
proxy();
// apply()
construct
construct()捕获器会在 new 操作符中被调用。对应的反射 API 方法为 Reflect.construct()
construct()必须返回一个对象
拦截操作
- new proxy(...argumentsList)
- Reflect.construct(target, argumentsList, newTarget)
参数
- target:目标构造函数。
- argumentsList:传给目标构造函数的参数列表。
- newTarget:最初被调用的构造函数。
const myTarget = function() {};
const proxy = new Proxy(myTarget, {
construct(target, argumentsList, newTarget) {
console.log('construct()');
return Reflect.construct(...arguments)
}
});
new proxy;
// construct()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!