国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

實現compose的五種思路

RayKr / 525人閱讀

好久沒有更新了,最近學習的過程中一直在用聯想的思維來去看問題,javascript是一門非常靈活的語言,集合了好多語言的特性和多種編程模式,對于compose的實現,就有非常多的思路,每一種思路都有自己的特點,實現之后,有種殊途同歸的快感。下面就是我總結的實現compose函數的五種思路。

面向過程

函數組合(reduce)

函數交織(AOP編程)

Promise(sequence)

Generator(yield)

什么是compose

簡單回顧一下composecompose就是執行一系列的任務(函數),比如有以下任務隊列,

let tasks = [step1, step2, step3, step4]

每一個step都是一個步驟,按照步驟一步一步的執行到結尾,這就是一個compose
compose在函數式編程中是一個很重要的工具函數,在這里實現的compose有三點說明

第一個函數是多元的(接受多個參數),后面的函數都是單元的(接受一個參數)

執行順序的自右向左的

所有函數的執行都是同步的(異步的后面文章會講到)

還是用一個例子來說,比如有以下幾個函數

let init = (...args) => args.reduce((ele1, ele2) => ele1 + ele2, 0)
let step2 = (val) => val + 2
let step3 = (val) => val + 3
let step4 = (val) => val + 4

這幾個函數組成一個任務隊列

steps = [step4, step3, step2, init]

使用compose組合這個隊列并執行

let composeFunc = compose(...steps)

console.log(composeFunc(1, 2, 3))

執行過程
6 -> 6 + 2 = 8 -> 8 + 3 = 11 -> 11 + 4 = 15
所以流程就是從init自右到左依次執行,下一個任務的參數是上一個任務的返回結果,并且任務都是同步的,這樣就能保證任務可以按照有序的方向和有序的時間執行。

實現compose的五種思路

所有思路的執行過程都是上面的例子,以下只講compose實現

面向過程

這個思路就是使用遞歸的過程思想,不斷的檢測隊列中是否還有任務,如果有任務就執行,并把執行結果往后傳遞,這里是一個局部的思維,無法預知任務何時結束。直觀上最容易結束和理解。

const compose = function(...args) {
  let length = args.length
  let count = length - 1
  let result
  return function f1 (...arg1) {
    result = args[count].apply(this, arg1)
    if (count <= 0) {
      count = length - 1
      return result
    }
    count--
    return f1.call(null, result)
  }
}

代碼地址

函數組合

這個思路是一種函數組合的思想,將函數兩兩組合,不斷的生成新的函數,生成的新函數挾裹了函數執行的邏輯信息,然后再兩兩組合,不斷的傳遞下去,這種思路可以提前遍歷所有任務,將任務組合成一個可以展開的組合結構,最后執行的時候就像推導多米諾骨牌一樣。

函數的組合過程

f1 = (...arg) => step2.call(null, init.apply(null, arg))
f2 = (...arg) => step3.call(null, f1.apply(null, arg))
f3 = (...arg) => step4.call(null, f2.apply(null, arg))

compose實現

const _pipe = (f, g) => (...arg) => g.call(null, f.apply(null, arg))
const compose = (...args) => args.reverse().reduce(_pipe, args.shift())

代碼地址

函數交織(AOP)

這個實現的靈感來自javascript設計模式中的高階函數,因為compose的任務在本質上就是函數執行,再加上順序,所以可以把實現順序執行放到函數本身,對函數的原型進行方法的綁定。方法的作用對象是函數,面向對象封裝的數據,面向函數封裝的是函數的行為。

需要對函數綁定兩個行為 beforeafterbefore執行函數多元部分(啟動),after執行函數單元部分

Function.prototype.before = function(fn) {
  const self = this
  return function(...args) {
    let result = fn.apply(null, args)
    return self.call(null, result)
  }
}

Function.prototype.after = function(fn) {
  const self = this
  return function(...args) {
    let result = self.apply(null, args)
    return fn.call(null, result)
  }
}

這里對函數進行方法的綁定,返回的是帶著函數執行的規則的另外一個函數,在這里是次序的排列規則,對返回的函數依然可以進行鏈式調用。
compose實現

const compose = function(...args) {
  let before = args.pop()
  let start = args.pop()
  if (args.length) {
    return args.reduce(function(f1, f2) {
      return f1.after(f2)
    }, start.before(before))
  }
  return start.before(before)
}

函數執行過程

step2.before(init).after(step3).after(step4)
fn3.after(step4)
fn3 = fn2.after(step3)
fn2 = fn1.before(step1)
fn1 = init -> step2 -> step3 -> step4

代碼地址

Promise

ES6引入了PromisePromise可以指定一個sequence,來規定一個執行then的過程,then函數會等到執行完成后,再執行下一個then的處理。啟動sequence可以使用
Promise.resolve()這個函數。構建sequence可以使用reduce
compose實現

const compose = function(...args) {
  let init = args.pop()
  return function(...arg) {
    return args.reverse().reduce(function(sequence, func) {
      return sequence.then(function(result) {
        return func.call(null, result)
      })
    }, Promise.resolve(init.apply(null, arg)))
  }
}

代碼地址

Generator

Generator主要使用yield來構建協程,采用中斷,處理,再中斷的流程。可以事先規定好協程的執行順序,然后再下次處理的時候進行參數(結果)交接,有一點要注意的是,由于執行的第一個next是不能傳遞參數的,所以第一個函數的執行需要手動調用,再空耗一個next,后面的就可以同步執行了。
generator構建

function* iterateSteps(steps) {
  let n
  for (let i = 0; i < steps.length; i++) {
    if (n) {
      n = yield steps[i].call(null, n)
    } else {
      n = yield
    }
  }
}

compose實現

const compose = function(...steps) {
  let g = iterateSteps(steps)
  return function(...args) {
    let val = steps.pop().apply(null, args)
    // 這里是第一個值
    console.log(val)
    // 因為無法傳參數 所以無所謂執行 就是空耗一個yield
    g.next()
    return steps.reverse.reduce((val, val1) => g.next(val).value, val)
  }
}

代碼地址

總結

github地址

github里面針對每一種實現包含了完成的demo案例,就在test.js里面,以上就是實現同步compose的五種思路,每一種思路的出發點都不一樣,但是實現的目的都是一樣的,可以看出javascript是非常靈活的,借助es6PromiseGenerator也可以很優雅的實現。后面會介紹compose的異步實現,在函數式編程來看,異步的本質應該就是Monad

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88856.html

相關文章

  • 轉:從框架看PHP五種境界及各自的薪資待遇

    摘要:語言行為及特征狀態看不懂任何英語技術,英語文檔,凡事沒有培訓部在搞的,只有英文文檔的東西國內一律沒大公司在用,都非主流,排斥英文文檔和新技術,以及各種超出他學習能力范圍的技術。 在撰寫此文前首先必須申明的是本人不鄙視任何一種框架,也無意于挑起PHP框架間的戰爭,更沒有貶低某個框架使用者的用意,本文純粹個人的看法。你可以認為我無知也好,或者裝逼也好,請不要試著在任何情況下,隨便發起言語的...

    Godtoy 評論0 收藏0
  • CSS之div嵌套問題及高度自適應問題五種實現--個人總結

    摘要:以下是在自己實習生面試的時候遇到的一個問題,事后自己也去總結了一下。 以下是在自己實習生面試的時候遇到的一個問題,事后自己也去總結了一下。問題描述如下:一個外層div里面嵌套兩個內部div,外層div高度固定(假設未知),內層上面的div高度固定,如何讓下面的div實現撐滿外層的div高度?看到過網上有類似的問題,但是大部分都是假設外層高度為100%或者是已知的,而我遇到的是外層高度雖...

    Jaden 評論0 收藏0
  • 實現垂直居中五種方法

    摘要:實現垂直居中的幾種方法分場景介紹包裹行內元素效果圖包裹行內塊級元素效果圖結構效果圖注容器若設置了再設置的無效,即會自動填滿的高寬若未設置,則自適應的實際寬高 實現垂直居中的幾種方法(分場景介紹) line-height (包裹行內元素) 123456788 12345555 .wrap { height: 100px; line-height:...

    qylost 評論0 收藏0
  • CSS進階篇--div中的內容垂直居中五種方法

    摘要:二內邊距法另一種方法和行高法很相似,它同樣適合一行或幾行文字垂直居中,原理就是利用將內容垂直居中,比如這段代碼的效果和法差不多。 一、行高(line-height)法 如果要垂直居中的只有一行或幾個文字,那它的制作最為簡單,只要讓文字的行高和容器的高度相同即可,比如: p { height:30px; line-height:30px; width:100px; overflow:hi...

    fjcgreat 評論0 收藏0

發表評論

0條評論

RayKr

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<