javascript函數式編程: 優雅的使用underscore進行函數編程

一等公民

函數是一等公民: 所謂一等公民①顧名思義身份高,JS任何只要是值能到達的地方,函數均可以去。html

字符串是一等公民,那麼函數也能夠擁有字符串同樣的特質java

var str = function(){return '123'} //儲存變量

var array = ['123',function(){return '456'}]//作數組成員

var concatStr = '123'+function(){return '456'}() //拼接

function concatFun (str,fn){
    return str + fn();
}
concatFun(123,function(){return '456'}) //作參數

return function(){return '123'} //被返回

複製代碼

正向咱們上一文使用call、apply舉例高級函數應該具有的特性:node

  • 能夠以函數做爲參數git

  • 能夠返回函數github

這正是underscore被普遍應用的緣由編程

操場報數遊戲

體育老師上課打太極前找同窗集合點到:設計模式

學生總數10人,報數順序自行定義:數組

因而咱們寫出了以下代碼:bash

(function () {
        var numberBill = [] //報數名單
        for (var number = 0; number < 10; number++) {
            numberBill.push('同窗 ' + number + ' 報數');
            if (number == 10) console.log('沒有學生了');
            if (number < 10) console.log('還剩:' + (10 - number - 1) + '名學生沒有報數');
        }
    })()
    
複製代碼

結果:app

VM85068:6 還剩:9名學生沒有報數
VM85068:6 還剩:8名學生沒有報數
VM85068:6 還剩:7名學生沒有報數
VM85068:6 還剩:6名學生沒有報數
VM85068:6 還剩:5名學生沒有報數
VM85068:6 還剩:4名學生沒有報數
VM85068:6 還剩:3名學生沒有報數
VM85068:6 還剩:2名學生沒有報數
VM85068:6 還剩:1名學生沒有報數
VM85068:6 還剩:0名學生沒有報數
複製代碼

這種編程方式很常見,誰都會寫,咱們通常叫這種編程方式稱之爲命令編程②,這個邏輯徹底在你掌握之中,你只要規定計算機在你想要的時候執行一些不一樣的動做就能夠了。

下文中出現的註解underscore方法會在文章最後註解講解,複雜的單獨抽離幾張講解。

function signInPositive(number) { //正序簽到
        var count = 1;
        return _.chain([])//①chain幹什麼的
                .push('同窗 ' + count + ' 正常報數')
                .tap(function (numberBill) { //②numberBill哪來的?
                    _.each(_.range(number),function(v,k){
                        if (count < number) numberBill.push('同窗 ' + (count++) + ' 正常報數')
                        console.log('還有'+(number-count)+'名同窗沒報數');
                    })
                }).value();//③
    }
    signInPositive(10)

複製代碼

雖然咱們勉強用函數編程實現了,可是有啥好處呢?沒啥好處,最起碼這個實現方法沒有凸顯出函數編程的價值,還不如命令編程容易理解。


我記得去年摩托羅拉出了一個模塊化手機,他的攝像頭,電池,外殼貌似都能拆卸換配件的,函數式編程也是這樣,咱們把能夠抽象抽象出來,再進行組合,進行模塊化


上面的例子循環是從(0--傳入的數字)正序循環,如果我不想從0開始呢?如果我倒序循環隨機循環呢?

改一下先把_.tap內部的_each循環去掉

function signIn(number) { //簽到
        return _.chain([])//①chain幹什麼的?見文章底部
                /*.push('同窗 ' + number + ' 正常報數')*/
                .tap(function (numberBill) { //②numberBill哪來的?見文章底部
                     numberBill.push('同窗 ' + (number+1) + ' 正常報數')
                     console.log(('同窗 ' + (number+1) + ' 正常報數'))
                    //我故意不在體內循環
                }).value();//③value幹啥的?見文章底部
    }

    
複製代碼

另外說明:

上文中
_.chain([])/*.push('同窗 ' + number + ' 正常報數')
複製代碼

這個鏈式操做加上push是爲了讓你們理解_.chain函數的做用,由於我在underscore文檔說過這樣句話:

說的很明白了,咱們可使用_.chain鏈式調用的同時,也支持JS 原生Arrayprototype中的push操做,而且知道你調用value()這些後面講,不要耽誤你們的思路。

那麼這個方法改爲這樣負責什麼職能呢?


就是負責存儲報數的同窗生成點名單,並不在意你怎麼循環,我只負責保存,因此由於咱們爲了靈活性模塊化吧內部的each操做剔除了,因此咱們必然要在其餘地方實現遍歷,並且最好能支持自定義循環...還要能保存上面方法返回的數據...


因而乎我想到了java中的模板引擎,好比jspfreemaker等,有這種設置startend以及步長的操做,經過步長:12-1-2循環,按照這個思路造個支持函數的輪子,不是恰好能夠解決這個問題嘛?

可是咱們彆着急,若果你瞭解underscore你會知道,這種東西你找它就行了!

  • 運氣不錯

哦?運氣真好,不當心找到兩個函數

咱們能夠用_.range_.reduce搭配使用,用_.range假冒一個數組,搭配reduce迭代,模擬出了一個相似模板引擎步長迭代器之類的東西。 是否是激起了你寫JS模板引擎的慾望呢? --別傻了,js不須要,即使須要相似grunt中的JST插件或者Underscore _.Templates也徹底夠用了,如今是個公司都搞先後分離模板引擎只適合博客小項目,或者大公司靜態化了...

先寫個DEMO測試一下:

var sum = _.reduce(_.range(1,10,1), function(memo, num){ return memo + num; }, 0
  
  這樣咱們就寫出了1-10的累加,連循環都沒寫
  
  ps:( 我之前看到個文章:30天不使用for循環 )
  
複製代碼
  • 歐耶

沒讓您失望吧,其實對於underscorelodash中的幾個重要函數什麼防抖節流閥...我想深刻開幾張講解的,正好我也深刻研究一下,畢竟好姿式但願你們都能用上。

function startPositive(start,end,signInFn){
        return _.reduce(
                _.range(start,end,1),
                function(acc,n){
                    return acc.concat(signInFn(n));
                },[])
    }

    var peapleArr = startPositive(0,10,signIn) //最終報數名單
    
複製代碼

完成了

作了什麼事?

咱們成功把耦合函數內部的循環抽離了,分爲了兩個函數, 主函數寫名單數組,複函數提供喊到方法而且拿到數組

  • 好處? 顯而易見,你的喊道方式不再用修改主函數了,你只要多寫幾個如:startInversestartRandom複函數提供方法便可

若你需求更加複雜或者更加優雅,你能夠把startPositive也進行抽離,改變步長達到正序逆序隨機的效果。


① 幾乎JS的書籍都提到這個術語,如今java8都積極響應函數編程,可是有些人依然認爲函數思想不如OO思想,評論區撕逼,管他呢,存在即合理。

② 命令編程,機器語言if else case控制,流程都是你每行代碼進行控制.而函數編程更加自由、優雅。


文中出現的underscore函數

  • _.chain
chain_.chain(obj) 
返回一個封裝的對象. 在封裝的對象上調用方法會返回封裝的對象自己, 
直道 value 方法調用爲止.
複製代碼

這個函數就是爲了優雅的使用鏈式調用準備的,value很簡單拿到最終值,畢竟鏈式調用的原理是返回對象自己,設計模式第一部分我就講了

粗略經過源碼咱們知道 underscore提供一個 value返回真正的數據,而且 return _wrapped返回原始數據結束

  • _.tap
tap_.tap(object, interceptor) 
用 object做爲參數來調用函數interceptor,而後返回object。這種方法的主要意圖是做爲函數鏈式調用 的一環, 爲了對此對象執行操做並返回對象自己。
複製代碼

可能有些人疑惑?爲啥你的

.tap(function (numberBill) { 
複製代碼

numberBill哪來的?

經過源碼咱們就知道實際上是他利用回調將咱們傳入的[]返回的。

  • _.reduce

剛纔已經講了使用方法,涉及到函數編程,我會後期單獨出幾章,而且仿造輪子

本文github源碼有部分註釋,搭配看,更加清晰。

  • 看狀況百度 其實不懂得東西沒那麼可怕,咱們只有不斷學習才能進步,不懂的東西不要百度,儘可能看看官網API,看一手資源。

  • 本文 -- 首發github

  • 開源交流羣:147255248

相關文章
相關標籤/搜索