js常用設計模式10-裝飾者模式 1,裝飾者模式實現飛機大戰 2,用AOP裝飾函數 3,試一試before的威力

能動態的給對象增加職責的方式稱爲裝飾者模式。
裝飾者模式能夠在不改變對象自身的基礎上,在程序運行期間給對象動態地添加職責。跟繼承相比,裝飾者模式靈活很多,“即用即付”,有點熱插拔那味了。

1,裝飾者模式實現飛機大戰

現在我們有一個飛機,初始1級的時候可以發射子彈,2級之後可以發射導彈,3級的時候可以發射原子彈:

//一個簡單地打飛機

var plane = {
  fire: function () {
    console.log('發射普通子彈')
  }
}

var missleDecorator = function () {
  console.log('發射導彈')
}

var atomDecorator = function () {
  console.log('發射原子彈')
}

var fire1 = plane.fire

plane.fire = function () {
  fire1()
  missleDecorator()
}

var fire2 = plane.fire
plane.fire = function () {
  fire2()
  atomDecorator()
}

plane.fire() 
// 分別輸出: 發射普通子彈   發射導彈    發射原子彈

2,用AOP裝飾函數

使用AOP也就是要在函數執行的before和after做一些處理,那麼我們就實現一下Function.prototype.before和Function.prototype.after:

//AOP裝飾函數

Function.prototype.before = function (beforeFn) {
  var _self = this
  //返回原函數和新函數的’代理‘函數
  return function () {
    //保證this不被劫持
    beforeFn.apply(this, arguments)
    return _self.apply(this, arguments)
  }
}

Function.prototype.after = function (afterFn) {
  var _self = this
  return function () {
    var result = _self.apply(this, arguments)
    afterFn.apply(this, arguments)
    return result
  }
}

可以在下面的例子中體會_self的用處

3,試一試before的威力

Function.prototype.before = function (beforeFn) {
      var _self = this
      //返回原函數和新函數的’代理‘函數
      return function () {
        //保證this不被劫持
        beforeFn.apply(this, arguments)
        return _self.apply(this, arguments)
      }
    }

在這個例子中,_self指的是document.getElementById.before這個函數上面,bofore的調用者,實際上是getElementById而不是document,因爲getElementById是最後一層的調用者,當document.getElementById = document.getElementById.before()之後,document.getElementById指向的就是before返回的函數,其中的this就是getElementById函數的調用者,也就是document。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <div id="button">11</div>
</head>

<body>
  <script>
    /**
     * 裝飾者模式和代理模式的區別
     * 裝飾者可以添加很多不同的東西,有點按需加載的意思
     * 代理只是專門處理一件事,需求一開始就是明確的
     */

    Function.prototype.before = function (beforeFn) {
      var _self = this
      //返回原函數和新函數的’代理‘函數
      return function () {
        //保證this不被劫持
        beforeFn.apply(this, arguments)
        return _self.apply(this, arguments)
      }
    }

    Function.prototype.after = function (afterFn) {
      var _self = this
      return function () {
        var result = _self.apply(this, arguments)
        afterFn.apply(this, arguments)
        return result
      }
    }

    document.getElementById = document.getElementById.before(function () {
      console.log('before')
    })
    var button = document.getElementById('button')

    window.alert = window.alert.before(function () {
      console.log(1)
    })
    alert(2)


  </script>
</body>

</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章