让前端飞前端杂记

高阶函数

2018-12-06  本文已影响2人  会飞小超人

高阶函数,至少满足下面之一:

高阶函数的应用

类型检验
const isType=function(type){
  return (obj)=>Object.prototype.toString.call(obj)===`[object ${type}]`
}

const isArray=isType('Array')
高阶函数实现AOP

AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块。

Function.prototype.before=function(beforefn){
  let _self=this
  return function(){
    beforefn.apply(this,arguments)
    return _self.apply(this,arguments)
  }
}

Function.prototype.after=function(afterfn){
  let _self=this
  return function(){
    let ret=_self.apply(this.arguments)
    afterfn.apply(this,arguments)
    return ret
  }
}

let func=function(){
  console.log(2)
}

func=func.before(function(){
  console.log(1)
}).after(function(){
  console.log(3)
})

这种使用AOP的方式来给函数添加职责,也是JavaScript语言中一种非常特别和巧妙的装饰者模式实现。

实现科里化(currying)

注:原书里的demo代码是存在一些问题的,这里进行了修正

const currying=function(fn){
  let args=[]
  return function(){
    if(arguments.length===0){
      return fn.apply(this,args)
    }else{
      [].push.apply(args,arguments)
      return arguments.callee
    }
  }
}

let cost=function(){
  let money=0
  for(let i=0,len=arguments.length;i<len;i++){
    money+=arguments[i]
  }
  return money
}
// 普通调用方式
console.log(cost(100,200,300)) 

// 科里化的调用方式
cost =currying(cost) 

cost(100)
cost(200)
cost(300)
console.log(cost())

// 或者这样也可以
console.log(cost(100)(200)(300)(400)())
uncurrying
Function.prototype.uncurrying=function(){
  let _self=this
  return function(){
    let obj=Array.prototype.shift.call(arguments)
    return _self.apply(obj,arguments)
  }
}

const push=Array.prototype.push.uncurrying()
(function(){
  push(arguments,4)
  console.log(arguments)
})(1,2,3)

通过uncurrying的方式,Array.prototype.push.call变成了一个通用的push函数。这样一来,push函数的作用就跟Array.prototype.push一样了,同样不仅仅局限于只能操作array对象。而对于使用者而言,调用push函数的方式也显得更加简洁和意图明了。
uncurrying还可以这样实现

Function.prototype.uncurrying=function(){
  let _self=this
  return function(){
    return Function.prototype.call.apply(_self,arguments)
  }
}
函数节流
const throttle=function(fn,interval){
  let _self=fn
  let timer
  let firstTime=true

  return function(){
    let args=arguments
    let _me=this
    if(firstTime){
      _self.apply(_me,args)
      return firstTime=false
    }
    if(timer){
      return
    }
    timer=setTimeout(function() {
      clearTimeout(timer)
      timer=null
      _self.apply(_me,args)
    }, interval||500);
  }
}

window.onresize=throttle(function(){
  console.log(1)
},500)
惰性加载函数

在第一次进入条件分支之后,在函数内部会重写这个函数,重写之后的函数就是我们期望的addEvent函数,在下一次进入addEvent函数的时候,addEvent函数里不再存在条件分支语句

const addEvent=function(elem,type,handler){
  if(window.addEventListener){
    addEvent=function(elem,type,handler){
      elem.addEventListener(type,handler,false)
    }
  }else if(window.attachEvent){
    addEvent=function(elem,type,handler){
      elem.attachEvent('on'+type,handler)
    }
  }
  addEvent(elem,type,handler)
}
上一篇下一篇

猜你喜欢

热点阅读