先看代碼:redux
let fn1 = function (x) { return x + 10; }; let fn2 = function (x) { return x * 10; }; let fn3 = function (x) { return x / 10; };
這是幾個簡單的運算方法,但想輸出的是一個多層函數嵌套的運行結果,即把前一個函數的運行結果賦值給後一個函數,固然咱們能夠寫成一下這樣:數組
let x = fn1(6); x = fn2(x); x = fn1(x); x = fn3(x);
但如今我就想用一個函數解決這種問題,形如:函數
compose(fn1, fn2, fn1, fn3)(6);
這個compose函數就是這篇文章介紹的——函數調用的扁平化,即把層級嵌套的那種函數調用(一個函數的運行結果看成實參傳給下一個函數的這種操做)扁平化,這就是compose函數。spa
那麼下面就是開始實現這個函數:code
首先咱們看參數,須要給出不肯定個數的函數:blog
function compose(...funcs) { //=>funcs:傳遞的函數集合 }
compose函數執行後跟個(),說明函數執行完再執行一個函數,即函數執行完會返回一個新函數,並且也會給出第一次調用函數時的參數:源碼
function compose(...funcs) { //=>funcs:傳遞的函數集合 return function proxy(...args) { //=>args:第一次調用函數傳遞的參數集合 } }
繼續往下進行,咱們須要判斷給出的函數集合的個數,若是沒有給函數,咱們只需將後一個的參數返回,若是隻給出一個函數,咱們只需把後一個的參數賦給這個函數去執行便可:io
function compose(...funcs) { //=>funcs:傳遞的函數集合 return function proxy(...args) { //=>args:第一次調用函數傳遞的參數集合 let len = funcs.length; if (len === 0) { //=>一個函數都不須要執行,直接返回ARGS return args; } if (len === 1) { //=>只須要執行一個函數,把函數執行,把其結果返回便可 return funcs[0](...args); } }; }
若是給出的參數集合是兩個及以上,那就是把前一個函數的執行結果賦給後一個函數,說到這,應該會想到一個知足這個需求的數組方法——reduce:console
function compose(...funcs) { //=>funcs:傳遞的函數集合 return function proxy(...args) { //=>args:第一次調用函數傳遞的參數集合 let len = funcs.length; if (len === 0) { //=>一個函數都不須要執行,直接返回ARGS return args; } if (len === 1) { //=>只須要執行一個函數,把函數執行,把其結果返回便可 return funcs[0](...args); } return funcs.reduce((x, y) => { }); }; }
但這裏須要注意的是,第一次執行的時候,參數x是個函數,以後再執行的時候x是個函數執行的結果,因此須要進行判斷:function
function compose(...funcs) { //=>funcs:傳遞的函數集合 return function proxy(...args) { //=>args:第一次調用函數傳遞的參數集合 let len = funcs.length; if (len === 0) { //=>一個函數都不須要執行,直接返回ARGS return args; } if (len === 1) { //=>只須要執行一個函數,把函數執行,把其結果返回便可 return funcs[0](...args); } return funcs.reduce((x, y) => { return typeof x === "function" ? y(x(...args)) : y(x) }); }; }
這樣,compose函數完成。
固然,redux源碼中的compose.js也能夠實現一開始想要的效果:
export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
但它和咱們寫的compose函數有些不一樣,它執行的順序是函數集合中的函數從後往前執行,因此結果也會不一樣:
compose(fn1, fn2, fn1, fn3)(6)); //=> 用第一個compose執行的結果是17,用redux的執行結果是116