一起扫荡JavaScript(十一)—— Proxy 与 JavaScript 中的 AOP
我们知道,Vue中双向绑定原理的实现,核心是改写了get、set方法,往其内部注入脚本,使得程序的读与写过程中执行了除其本身读与写之外其他逻辑,而这个属性重定义的过程Vue2.0及以前采用的是Object.defineProperty()。Vue3.0则使用Proxy来实现这一过程。而本次我们一起来聊聊Proxy吧。
Proxy,顾名思义,代理,就像同样做一件事情,你亲自做也是做,委托给另外的人帮你做也是做,这就是代理,代替你打理。而且,它还可以帮我们做一些其他的事情,比如拦截器,校验器等。
看一下下面这段代码:
const targetObj = {
name: 'dorsey',
age: 25
}
const obj = new Proxy(targetObj, {
get(target, key) {
console.log('这里是重写之后的get方法,它已经拿到了需要读取的属性:' + key);
return target[key];
}
});
console.log(targetObj.name); // dorsey
console.log('===================');
console.log(obj.name); // 这里是重写之后的get方法,它已经拿到了需要读取的属性:name
新的代理对象改写了get方法,这样当需要从读值这里入手做一些改变时,就可以按照你的需求添加你所需要的逻辑。
就像下面的数据校验与拦截:
const anotherObj = new Proxy(targetObj, {
set(target, key, value) {
if(key === 'age' && 'number' !== typeof value) throw 'age属性不是Number类型, 请重新设置'
target[key] = value;
}
});
targetObj.age = '100';
console.log(targetObj.age); // 100
console.log('===================');
anotherObj.age = '100'; // Uncaught age属性不是Number类型, 请重新设置
console.log(anotherObj.age);
你可以发现,Proxy主要做的事情就是在源对象的基础上,加入一些自定义行为,但它又只是做了代理,本质上代理虽然能改变原对象,也能将结果正常反馈给源对象,但大多数情况下,代理不会去改变原对象本身的函数或值,也就是源对象还是源对象,但它又因为多了一层代理,可以在不改变源对象的情况下做更多的事情。而这,在我看来,就是一个AOP,就是一种面向切面的编程。
什么意思?或者说简单的需要怎么理解这个AOP,怎么理解面向切面?
切面,看看下图(这是切线,但实在画不出一个球,理解就好啦):
切面切面,从远方而来,触之即走,无痕无留,简单的就是说,如何在源程序(原类,原对象)不改变的前提下,统一化加入一些自定义功能?
那为什么会有这样的需要?这其实很常见,简单的用户输入输出,传递至后台,要校验吧?某个用户具备哪些权限,也需要校验吧?为便于以后定位问题所在,要有日志吧?但是,对于源对象而言,这些日志,校验实际上跟他们无关,尽管你可以直接写在里面,但这会使程序很臃肿,得不偿失,而这样万花丛中过,片叶不沾身的理念就此应运而生,它就是 —— AOP, 也就是面向切面编程。
这个AOP能不能通过JavaScript来实现呢?当然可以。
简单的实现如下:
function factory (fn, _before, _after) {
return function () {
_before && 'function' === typeof _before && _before.call(this);
fn.call(this);
_after && 'function' === typeof _after && _after.call(this);
}
}
// 原函数
function hello () {
this.a = 'dorsey';
console.log('你好啊');
}
// 前置通知
function beforeFn () {
console.log('前置通知');
console.log(this.a);
}
// 后置通知
function afterFn () {
console.log('后置通知');
console.log(this.a);
}
let hello1 = factory(hello, beforeFn, afterFn);
hello();
console.log('=========================');
hello1();
原来的hello函数还是原来的hello函数,在必要的时候,可以通过这个添加一些前置任务(比如校验、拦截)或者后置任务(比如日志),这样既达到了功能调整,又不会使代码非常冗余和高耦合,正如AOP的理念 —— 万花从中过,片叶不沾身。
共同学习,写下你的评论
评论加载中...
作者其他优质文章