面向切面编程
- 面向切面编程在java中提出这类概念
- 但是在js没有束缚和约定,只需要按编程思想来实现原理
- 在js中使用function或class实现面向切面编程
面向切面概念
- AOP (Aspect Oriented Programming) 面向切面编程
- 主要实现目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果
- 类比
- 用刀切西瓜,西瓜红壤面就是切面,可以两驱切面的圆周和面积
- 无侵入式的干扰
- 只需要两篇,比如开头和结尾截取, 而非随意切,横切,竖切
- 处理业务某个中间的部分,提取和隔离,不对具体业务干扰
- 比如在业务中穿插了一些代码,比如网页性能检测,用js埋点
- 不在里面埋点,在整体业务上加东西,在函数之前或之后执行,如果哪天有热插拔的需求,把函数抽走,也不影响原来的业务
- 埋点函数和原来业务不会影响和混淆
代码实现
-
比如, 统计当前所有函数谁耗时最长,最性能优化
-
1 )侵入式演示: 每个函数前后加代码
function test() {console.time()alert(2)console.timeEnd() }
-
2 ) 在原型链上添加函数优化,先忽略这个 console.time/timeEnd 统计函数
-
2.1 只添加before函数到原型链上
function test() {alert(2) }Function.prototype.before = function (fn) {fn() // 执行前置任务this.apply(this, arguments) // 执行自身 } // 演示 test.before(function() {alert(1) })
-
2.2 只添加after函数到原型链上
function test() {alert(2) }Function.prototype.after = function (fn) {// 先执行 this本身,再执行回调this.apply(this, arguments) // 执行自身fn() // 执行前置任务 }// 演示 test.after(function() {alert(3) })
-
2.3 将before和after函数添加到原型链上
function test() {alert(2) }Function.prototype.before = function (fn) {fn() // 执行前置任务// return this.apply(this, arguments) // 执行自身 // 这里可以return 用于其他this.apply(this, arguments) // 执行自身 }Function.prototype.after = function (fn) {// 先执行 this本身,再执行回调this.apply(this, arguments)fn() // 执行后置任务 }// 演示 test.before(function() {alert(1) }) test.after(function() {alert(3) })
- 这时候默认函数被执行了2遍,需要优化
-
-
5 ) 继续优化重复执行的默认函数,将this只在before中执行
function test() {alert(2) }Function.prototype.before = function (fn) {fn() // 执行前置任务// return this.apply(this, arguments) // 执行自身 // 这里可以return 用于其他this.apply(this, arguments) // 执行自身 }Function.prototype.after = function (fn) {// 先执行 this本身,再执行回调// this.apply(this, arguments) // 执行自身fn() // 执行后置任务 }// 演示 test.before(function() {alert(1) }) test.after(function() {alert(3) })
- 以上是原型链中添加, 这完全没问题,但是写了两次
-
6 ) 支持链式调用版本优化
function test() {alert(2) }Function.prototype.before = function (fn) {var _self = thisreturn function () {fn.apply(this, arguments)_self.apply(this, arguments)} }Function.prototype.after = function (fn) {var _self = thisreturn function () {_self.apply(this, arguments)fn.apply(this, arguments)} }
- 基于以上代码,如果这样测试, 测试1:
// 演示 test.before(function() {alert(1) }).after(function() {alert(3) })()
- 它的输出顺序是
after before 1 2 before over 3 after over
- 它的输出顺序是
- 如果这样测试, 测试2
test.after(() => {alert(3)}).before(() => {alert(1)})()
- 它的输出顺序是
before 1 after 2 3 after over before over
- 它的输出顺序是
- 基于以上代码,如果这样测试, 测试1:
- 注意的是 this 指针的引用,使用function而非箭头函数
- 以上示例,不管先调用before还是after
- 都会先执行before中的fn
- 之后是默认函数
- 最后才是after的fn
- 输出顺序都是: 1 2 3
7 ) 链式调用,并支持异常断开
function test() {alert(2)// return false // 注意这里可以打开,尝试return 'test'
}Function.prototype.before = function (fn) {var _self = thisreturn function () {if (fn.apply(this, arguments) === false) {return false}return _self.apply(this, arguments)}
}Function.prototype.after = function (fn) {var _self = thisreturn function () {var result = _self.apply(this, arguments)if (result === false) return falsefn.apply(this, arguments)return result // 这里注意}
}// 演示
test.before(function() {alert(1)
}).after(function() {alert(3)
})()
- 注意以上 === 判断中,关于 false 和 undefined区别
- undefined 意味着成功,只有主动 false 时,才可以
- 还可以换一种写法,比如 return true时,继续,其他都拒绝执行
- 每一层都可以 return , 可return成任意值,只有false才会阻断