高阶函数

作者: 会飞小超人 | 来源:发表于2018-12-06 14:35 被阅读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)
    }
    

    相关文章

      网友评论

        本文标题:高阶函数

        本文链接:https://www.haomeiwen.com/subject/sdeycqtx.html