JS高階編程技巧--compose函數

先看代碼:redux

let fn1 = function (x) {
    return x + 10;
};
let fn2 = function (x) {
    return x * 10;
};
let fn3 = function (x) {
    return x / 10;
};
  console.log(fn3(fn1(fn2(fn1(6)))));

這是幾個簡單的運算方法,但想輸出的是一個多層函數嵌套的運行結果,即把前一個函數的運行結果賦值給後一個函數,固然咱們能夠寫成一下這樣:數組

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
相關文章
相關標籤/搜索