Proxy代理器
基本用法
- ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例
var proxy = new Proxy(target, handler)target参数表示所要拦截的目标对象handler参数也是一个对象,用来定制拦截行为new Proxy()之后返回一个对象,可以通过该对象,对target进行操作
个人理解:我们来做个类比,
A相当于target,B相当于proxyget(target, propKey, receiver)- 作用:拦截对象属性读取。比如
proxy.foo 和 proxy['foo'] - 参数
target:传进Proxy构造函数的目标对象propKey:读取某个属性时的属性名receiver:执行Proxy构造函数后,返回的实例
- 作用:拦截对象属性读取。比如
set(target, propKey, value, receiver)- 作用:拦截对象属性的设置。比如
proxy.foo = v或proxy['foo'] = v,返回一个布尔值 - 参数
value:读书某个属性时的属性值
- 作用:拦截对象属性的设置。比如
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循环,返回一个数组 - 该方法返回目标对象所有自身的属性的属性名,而
Object.keys()的返回结果仅包括目标对象自身的可遍历属性
- 作用:拦截
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)```javascript // 案例一 const obj = { age: 18 }; const handler = { get: function (target, propKey, receiver) { return target[propKey] }, set: function (target, propKey, value, receiver) { // 可以在方法上做一些处理,比如阻止修改原型 if (propKey === ‘proto‘) { return false; } target[propKey] = value; return true; }, has: function (target, propKey) { return target[propKey] !== undefined }, deleteProperty: function (target, propKey) { if (propKey === ‘proto‘) { return false; } delete target[propKey]; return true; }, getOwnPropertyDescriptor: function (target, propKey) { return Object.getOwnPropertyDescriptor(target, propKey); }, defineProperty: function (target, propKey, propDesc) { // 外部调用Object.defineProperties(proxy, propDescs),会逐次的调用这个函数 Object.defineProperty(target, propKey, propDesc); return true; }, preventExtensions: function (target) { // 即使不传入target,也要调用Object.preventExtensions()。不然在外部调用,会报错 Object.preventExtensions(); return true }, getPropertypeOf: function (target) { return Object.getPrototypeOf(target); }, isExtensible: function (target) { return Object.isExtensible(target) }, setPropertypeOf: function (target, proto) { Object.setPrototypeOf(target, proto); return true } }
- 作用:拦截 Proxy 实例作为构造函数调用的操作,比如
const proxy = new Proxy(obj, handler);
<a name="wsUyk"></a>## 回收Proxy代理- `Proxy.revocable(target, handle)`- 作用:返回一个可取消的 Proxy 对象,该对象的`proxy`属性是`Proxy实例`,`revoke`属性是一个函数,可以取消`Proxy`实例- 当执行`revoke函数`之后,再访问`Proxy实例`,就会抛出一个错误```javascriptlet target = {};let handler = {};let {proxy, revoke} = Proxy.revocable(target, handler);proxy.foo = 123;proxy.foo // 123revoke();proxy.foo // TypeError: Revoked
this问题
// 案例一:this隐式绑定const target = {m: function () {console.log(this === proxy);}};const handler = {};const proxy = new Proxy(target, handler);target.m() // falseproxy.m() // true
// 案例二:this由于隐式绑定,而产生的问题let set = new WeakMap();let target = {get value() {return set.get(this);},set value(val) {set.set(this, val)}}target.value = 456;let proxy = new Proxy(target, {});console.log(target.value); // 456console.log(proxy.value); // undefined
// 案例三// 有些原生对象的内部属性,只有通过正确的this才能拿到,所以 Proxy 也无法代理这些原生对象的属性const target = new Date();const handler = {};const proxy = new Proxy(target, handler);proxy.getDate(); // TypeError: this is not a Date object.
proxy 的应用
// 案例一:用proxy实现双向绑定const data = { text: '' };const input = document.querySelector('input');const p = document.querySelector('p');const handler = {set(target, key, value) {target[key] = value;// 数据变化 ——> 视图变化input.value = value;p.innerText = value;return true;}}const proxy = new Proxy(data, handler);input.onchange = function (e) {// 视图变化 ——> 数据变化proxy.text = e.target.value;}
