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


先看代碼:

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函數。

 

那么下面就是開始實現這個函數:

首先我們看參數,需要給出不確定個數的函數:

function compose(...funcs) {
    //=>funcs:傳遞的函數集合
}

 

compose函數執行后跟個(),說明函數執行完再執行一個函數,即函數執行完會返回一個新函數,而且也會給出第一次調用函數時的參數:

function compose(...funcs) {
    //=>funcs:傳遞的函數集合
    return function proxy(...args) { 
      //=>args:第一次調用函數傳遞的參數集合

    }    
}

 

繼續往下進行,我們需要判斷給出的函數集合的個數,如果沒有給函數,我們只需將后一個的參數返回,如果只給出一個函數,我們只需把后一個的參數賦給這個函數去執行即可:

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:

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 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM