面向对象(OOP)做为经典的设计范式,对于咱们来讲可谓无人不知,还记得咱们入行起始时那句经典的总结吗-万事万物皆对象。
是的,基于OOP思想封装、继承、多态的特色,咱们会天然而然的遵循模块化、组件化的思惟来设计开发应用,以到达易维护、可扩展、高复用的目的。
既然OOP这么多优势,那么常常被你们提起的面向切面编程(AOP)是什么回事呢,下面咱们就一块儿来看一下。javascript
第一步仍是要知道aop是什么,先个来自维基百科的解释:java
面向侧面的程序设计(aspect-oriented programming,AOP,又译做面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。
侧面的概念源于对面向对象的程序设计的改进,但并不仅限于此,它还能够用来改进传统的函数。react
其从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来.
业务逻辑的代码中再也不含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系经过侧面来封装、维护. 这样本来分散在在整个应用程序中的变更就能够很好的管理起来。git
确实有点那么不太清晰,有点乱。不过在乱以前,咱们能够选能理解的部分先看一下:github
简而言之,AOP是针对业务处理过程当中的切面(即非业务逻辑部分,例如错误处理,埋点,日志等)进行提取.
它所面对的是处理过程当中的某个步骤或阶段,以得到逻辑过程当中各部分之间低耦合性的隔离效果(目的是下降耦合)。
具体到实现来讲就是经过动态的方式将非主关注点部分插入到主关注点(通常是业务逻辑中)编程
说了这么多,可能不太明白,仍是一块儿看代码吧。markdown
很广泛的这么个场景,须要点击按钮以后进行信息上报。 假设咱们有这么个logger的工具,能够进行上报:app
const logger = console.log //引入便可使用 logger('按钮被点击了') 复制代码
那么,咱们直接撸起来吧:异步
const doSomething = ()=>{ console.log('doSomething') } let clickHandler = ()=>{ logger('doSomething以前') // n行代码 doSomething() logger('doSomething以后') //n 行代码 } 复制代码
看起来也没什么的,简单粗暴。
若是有30个按钮,每一个业务逻辑不一样,都须要埋这个点(假设打点信息一致)。
咱们30个函数里面,都要手动写这个方法的话,这也太坑爹了吧。
主要是与业务代码严重耦合,哪天不当心动了点其余内容,手抖误删了,就gg了。
后续维护的时候,简直噩梦。
仔细看一下,这不就是符合AOP的使用前提吗,那么试试AOP吧。模块化
根据前面提的,能够划分下关注点。
主关注点 | 侧关注点 |
---|---|
业务逻辑(doSomething) | 埋点信息 logger |
前面提到AOP关注的是步骤具体到例子来讲其实就是插入logger的步骤。
插入时机无非时业务逻辑执行以前或者以后的阶段。
具体实现起来也不那么困难
具体到js来讲,因为语言自己的特性,天生就具备运行时动态插入逻辑的能力。
重点在于在原函数上增长其余功能并不改变函数自己。
毕竟函数能够接受一切形式的参数,固然函数也不例外了。
当传入一个函数的时候,咱们要对其操做的余地就很大了,
保存原函数,而后利用后续参数加上call或apply,就能够达到咱们的目的。
此外为了给函数都增长一个属性,咱们在原型上操做就好了。
网上太多相似实现了,直接看代码好了:
// action 即为咱们的侧关注点,即logger Function.prototype.after = function (action) { //保留当前函数,这里this指向运行函数即clickHandler var func = this; // return 被包装过的函数,这里就能够执行其余功能了。 // 而且该方法挂在Function.prototype上, // 被返回的函数依然具备after属性,能够链式调用 return function () { // 原函数执行,这里不考虑异步 var result = func.apply(this, arguments); // 执行以后的操做 action.apply(this,arguments); // 将执行结果返回 return result; }; }; // before 实现相似,只不过执行顺序差异而已 Function.prototype.before = function (action) { var func = this; return function () { action.apply(this,arguments); return func.apply(this, arguments); }; }; 复制代码
那么咱们使用AOP改造以后的代码就以下了:
const doSomething = ()=>{ console.log('doSomething') } let clickHandler = ()=>{ // n行代码 doSomething() //n 行代码 } clickHandler = clickHandler.before(()=>{ logger('doSomething以前') }).after(()=>{ logger('doSomething以后') }) clickHandler() // 执行结果和预期一致 复制代码
到这里就实现了面向切面编程,咱们的业务逻辑里面只管业务自己,侧关注点经过这种方式来动态引入,与主逻辑解耦,更加纯净、易于维护。
到这里,简单的AOP就介绍完成了。利用这种模式结合咱们js自己的特性,能够尝试更多的可能。 例如咱们react中常见的HOC、es7的装饰者模式、HOF等,不少时候不得不感叹大牛们思想的精髓,会让咱们有种顿悟的感受。本文抛砖引玉,共同窗习啦,对本身是总结和提升,更但愿能帮助到须要的小伙伴。更多文章请移步个人博客
AllyTeam - 用AOP改善javascript代码
深刻浅出 Javascript Decorators 和 AOP 编程