前端小技巧: 面向切面编程在前端代码中的应用

面向切面编程

  • 面向切面编程在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 = this
      return function () {
        fn.apply(this, arguments)
        _self.apply(this, arguments)
      }
    }
    
    Function.prototype.after = function (fn) {
      var _self = this
      return 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
        
  • 注意的是 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 = this
  return function () {
    // 下面的 if 写法比较麻烦,但这样写算比较清晰吧
    if (fn.apply(this, arguments) === false) {
      return false
    }
    return _self.apply(this, arguments)
  }
}

Function.prototype.after = function (fn) {
  var _self = this
  return function () {
    var result = _self.apply(this, arguments)
    if (result === false) return false
    fn.apply(this, arguments)
    return result // 这里注意
  }
}

// 演示
test.before(function() {
  alert(1)
}).after(function() {
  alert(3)
})()
  • 注意以上 === 判断中,关于 false 和 undefined区别
  • undefined 意味着成功,只有主动 false 时,才可以
  • 还可以换一种写法,比如 return true时,继续,其他都拒绝执行
  • 每一层都可以 return , 可return成任意值,只有false才会阻断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值