做有追求的coder - Redux進階compose方法的實現與解析

鮑康霖發表於2018-07-05

前言

在使用redux的過程中,不免要用到中介軟體,用到中介軟體,就免不了使用compose方法來解決中介軟體層層巢狀的問題,那麼redux中的compose方法實現原來是怎樣的呢?

用法

compose(...functions)

這是函數語言程式設計中的方法,為了方便,被放到了 Redux 裡。 當需要把多個 store 增強器(中介軟體) 依次執行的時候,需要用到它。

引數

(arguments): 需要合成的多個函式。預計每個函式都接收一個引數。它的返回值將作為一個引數提供給它左邊的函式,以此類推。例外是最右邊的引數可以接受多個引數,因為它將為由此產生的函式提供簽名。(譯者注:compose(funcA, funcB, funcC) 形象為 compose(funcA(funcB(funcC()))))

返回值

(Function): 從右到左把接收到的函式合成後的最終函式。

一個例子

import {componse} from 'redux'
function add1(str) {
	return 1 + str;
}
function add2(str) {
	return 2 + str;
}
function sum(a, b) {
	return a + b;
}
let str = compose(add1,add2,add3)('x','y')
console.log(str)
//輸出結果 '12xy'

複製程式碼

上面程式碼compose(add1,add2,add3)('x','y')方法實際上等同於下面的程式碼

add1(add2(add3('x','y')))
複製程式碼

一步步解析compose方法內部的實現,首先從用法compose(add1,add2,add3)('x','y')來看,compose方法的執行結果顯然返回的是一個函式.

function compose(...fns){
    return function(...args){ //  args => ['x','y']
        ...處理程式碼        
    }
}
複製程式碼

由於只有最右邊的中介軟體才能接受多個引數,我們先將它取出來,將多個的引數單獨傳給他 其他的中介軟體函式都只有一個引數,就是他右側中介軟體函式執行之後的返回值

function compose(...fns){
    return function(...args){ //  args => ['x','y']
        let last = fns.pop(); // sum
        fns.reduceRight((val,fn)=>{
            return fn(val)
        },last(...args))
    }
}
複製程式碼

我們來分析一下 fns.reduceRight中的執行

fns.reduceRight((val,fn)=>{
    return fn(val)
},last(...args))
複製程式碼

第一次 val 為 sum('x','y') fn為 add2

第二次 val 為 add2(sum('x','y')) fn 為 add1

執行結束 返回 add1(add2(sum('x','y')));

這樣,compose的執行原理就基本解釋清楚了,但是,這個只是redux中compose方法以前的實現方法.現在redux中對於compose的實現換了一種更加優雅的方法

redux中compose方法最新實現

它摒棄了原來將最後一箇中介軟體函式提取出來的方法,直接一行程式碼將內部邏輯實現了

    function compose(...fns){
        return fns.reduce((a,b)=>(...args)=>a(b(...args)))
    }
複製程式碼

我們還是以compose(add1,add2,sum)('x','y')為例對fns.reduce進行解析

    fns.reduce((a,b)=>(...args)=>a(b(...args)))
    //展開
    function compose(...fns){
    	return fns.reduce((a,b)=>{
    		return (...args)=>{
    			return a(b(...args))
    		}
		}
	}
})
//第一次 執行 a為add1 b為add2
//第二次 執行 a為 (...args)=>{
                    return add1(add2(...args))
                }
            b為 sum
//執行結束 返回 
(...args)=>{
	return ((...args)=>{
        		return add1(add2(...args))			
        	})(sum(...args))
}
//為了能更好的區分邏輯,我把這裡稍微改一下
(...args2)=>{
    return  ((...args)=>{
                return add1(add2(...args))
            })(sum(...args))
}
//等價於
(...args2)=>{
    add1(add2(sum(...args2)))
}
//args2替換為['x','y']
add1(add2(sum('x','y')))
複製程式碼

邏輯總算是理清楚了,真的是有夠繞的

做有追求的coder - Redux進階compose方法的實現與解析

結語

每次原始碼閱讀與解析,總是能夠在不經意的角落發現令人讚歎的程式碼,程式設計的魅力大概就在這裡吧

如果覺得還可以,能在諸君的編碼之路上帶來一點幫助,請點贊鼓勵一下,謝謝!

相關文章