after函数与before函数

1,126 阅读3分钟

应用了函数柯里化的after函数

用法:此函数在经过你规定的调用次数后才会执行

什么是函数柯里化
维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
这里不做过多介绍了,该知道的都知道了,不知道的慢慢了解


// 首先定义一个after函数,其中有两个参数  
// count是用来做减法决定你函数是何时执行的  
// callback为执行的回调
function after (count, callback) {
  let total = 0 // 这里声明一个计数器,用以增强函数功能(不需要也可以去掉)
  return function (value) { // value接收fn(1)中1这个值
    total += value
    if (--count == 0) {
      // 若函数做减法到0时,便开始执行回调,也就是执行下方fn中的内容,顺手将total也传过去
      callback(total)
    }
  }
}

let fn = function (params) {
  console.log('问:我是世界第几帅?', '答:第' + params + '!')
}

let handsomeBoy = after(3, fn)

handsomeBoy(1)
handsomeBoy(1)
handsomeBoy(1) //问:我是世界第几帅? 答:第3!

以上就是一个after函数,因为if判断的不通过,前两次的 handsomeBoy(1) 函数调用不会被执行,等到第三次才会被执行,让我成为世界第三帅。

以上after函数的实现,如果继续执行 handsomeBoy(1) 函数到第四次、第五次...都不会有任何反应,那么如何动摇我世界第三帅的名次呢?

if (--count <= 0) { // 这里修改一个小符号
    callback(total)
}

handsomeBoy(1)
handsomeBoy(1)
handsomeBoy(1) //问:我是世界第几帅? 答:第3!
handsomeBoy(1) //问:我是世界第几帅? 答:第4!
handsomeBoy(6) //问:我是世界第几帅? 答:第10!

if语句中 (--count == 0) 修改为 (--count <= 0),在经过你所限制的3次之后,每次调用,都会执行。

应用了AOP面向切片编程的before函数

主要解决在修改别人函数时,为了不直接插入自己代码,造成耦合度过高,与本着不侵入别人代码且提高可读性的原则

原函数:

function say (a, b) {
  console.log(a + '开眼了' + b)
  ...业务逻辑
}

侵入式写法

function say (a, b) {
  before()
  console.log(a + '开眼了' + b)
  ...业务逻辑
  after()
}

function before(){
  console.log('前-入侵入侵入侵!')
}

function after(){
  console.log('后-入侵入侵入侵!')
}

say('真是给我', '!')

输出

前-入侵入侵入侵!
真是给我开眼了!
后-入侵入侵入侵!



此写法虽然对接盘开发者来说很方便快捷,但其中却包含很多缺点

  • 每个函数都要写一遍,效率低
  • 为了新增的需求,去改动本来的代码,耦合性变高
  • 可读性低,让后来者看不懂代码的真实意图,一个好好的函数,为什么要加before、after

AOP写法

其中使用了原型链

function speak (a, b) {
  console.log(a + '开眼了' + b)
  ...业务逻辑
}

// 在原型链上添加一个before方法
Function.prototype.before = function (fn) {
  // 谁调用this,this就指向谁,这里的this指向speak函数
  let that = this
  return function () {
    // 这里的this指向window
    // fn就是执行的下方.before中的函数内容
    fn()
    // that为speak,也就是原函数
    // 展开arguments是为了能够拿到所有参数
    that(...arguments)
  }
}

let beforeSpeak = speak.before(function () {
  console.log('小刀扎屁股')
})

beforeSpeak('真是给我', '!')

输出
小刀扎屁股
真是给我开眼了!


通过面向切片的方式,我们既完成了需求也保证了原函数的完整性,还可以间接的传递给后来者一个信息,在.before中所添加的内容,是在后期更新迭代的需求中所添加的,不是本来就有的。