前言javascript
Proxy, 也就是代理。设计模式中有一种叫作代理模式,能够用来实现AOP,拦截器。后端常常会用到。html
那什么是代理模式,这样说吧。快到5.20了你想追个妹子,惋惜没她联系方式,恰好你朋友认识她,你就请你的朋友代理你,捎信给她,表诉你的爱慕之情。就有点像读书那会的送情书。前端
代理在生活中很常见,董事长和助理之间是代理关系,你的领导和你之间也是代理,领导安排活,你就干。领导 ~ 你 ~ 活,这三者之间,你就是属于代理人,领导只管安排,而后你处理好,把结果给他看。是否是很简单?java
开始进入正题es6
ES6 原生提供了 Proxy API , 用来生成 Proxy 实例。后端
那 Proxy 在前端有什么用处呢设计模式
①、拦截和监视外部对对象的访问闭包
②、下降函数或类的复杂度app
③、在复杂操做前对操做进行校验或对所需资源进行管理函数
运用
1、如何使用 Proxy
let proxy = new Proxy(target, handler);
target 参数表示须要拦截的目标对象。
handler 参数是一个对象,用来定制拦截行为。
handler 支持 13 种拦截行为,以下:
get(target, property, receiver) //拦截对象属性的读取 set(target, property, value, receiver) //拦截对象属性的设置 has(target, property) // 拦截 property in target 的操做,返回布尔值 deleteProperty(target, property) // 拦截 delete target[property] 的操做,返回布尔值 apply(target, context, args) //拦截 Proxy实例做为函数调用的操做 construct(target, args) // 拦截 Proxy 实例做为构造函数调用的操做 ownKeys(target) //如下方法,分别拦截 Object对象 下对应的操做 //如 definedProperty 拦截 Object.defineProperty(proxy) 操做。 getOwnPropertyDescriptor(target, propKey) defineProperty(target, propKey, propDesc) preventExtensions(target) isExtensible(target) getPrototypeOf(target) setPrototypeOf(target, proto)
Proxy 功能强大,咱们常常用到的是它的 get, set 方法。
举个栗子,拦截某个对象的属性读写。
let obj = { name: 'jk', age: 25 } let handler = { get(target, property, receiver) { let value = target[property]; console.log(`get ${property} value: ${value}`); return value; }, set(target, property, value, receiver) { console.log(`set ${property} value: ${value}`) } } let proxy = new Proxy(obj, handler); proxy.name // get name value: jk // jk proxy.age = 26; // set name value: 26 // 26
2、Proxy的用处
有的童鞋就会问,Proxy 到底有什么用处呢? 固然有用了,下面介绍下我能想到的用处。
① 实现 AOP
运用 Proxy 的 apply 方法。
咱们有时候但愿 在函数执行以前,先运行某函数,函数执行以后,再运行某函数。
先定义几个函数,后面会用到。
const log = (...args) => console.log(...args); const test = () => log('test'); const beforeTest = () => log('beforeTest'); const afterTest = () => log('afterTest');
最基本的实现:
const testBetter = (cur, before, after) => {
before();
cur();
after();
}
testBetter(test, beforeTest, afterTest);
说实话,我以为上面的代码就能够了,没什么很差。。。。。
固然也有其余的方法:
以前没有 Proxy 的作法是利用 闭包实现一个装饰器模式,(ES7已实现 Decorator),以下:
Function.prototype.before = function(beforefn) { let _self = this; //存储 当前函数 return function() { beforefn.apply(_self, arguments); return _self.apply(this, arguments); } } Function.prototype.after = function(afterfn) { let _self = this; //存储 当前函数 return function() { var ret = _self.apply(this, arguments); afterfn.apply(this, arguments); return ret; } } const testBetter = test.before(beforeTest).after(afterTest); testBetter(); // beforeTest // test // afterTest
如今,咱们有了 Proxy, 就能够更方便了。能够运用 Proxy 的 apply 方法来实现。
const createProxy = (target, handler) => new Proxy(target, handler); const createAop = (current, before, after) => { return createProxy(current, { apply(target, context, args) { before.call(context); Reflect.apply(...arguments); // target.apply(context, args); after.call(context) } }) } const testProxy = createAop(test, beforeTest, afterTest); testProxy(); // beforeTest // test // afterTest
咱们能够用 boforeTest 和 afterTest 来打印一些咱们调试所须要的信息,不就实现了一个简单的日志功能吗。
②、咱们也能够用 Proxy 的 get 来过滤数据。
let grade = { age: [4, 5, , undefined, 6, 7, ,null, 8, , 9, 10] } //去除undefined 和 null let filterArr = (arr) => arr.filter(item => item !== undefined && item !== null); let proxy = new Proxy(grade, { get(target, property, receiver) { let value = target[property]; if ( Array.isArray(value) ) { return Reflect.apply(filterArr, window, [value]); } } }) proxy.age; // [4, 5, 6, 7, 8, 9, 10]
还能够实现其余的功能:拦截,数据校验,私有属性等等。
3、Proxy 如何取消。
Proxy.revocable方法返回一个可取消的 Proxy 实例。
let {proxy, revoke} = Proxy.revocable(target, handler);
文章只是叙述了 Proxy 的冰山一角,更多内容请移步个人参考连接。
今天先写到这里,若有错误之处,还望指出。谢谢。
参考
http://es6.ruanyifeng.com/#docs/proxy
https://www.w3cplus.com/javascript/use-cases-for-es6-proxies.html