JavaScript 高階函數

2023-02-08 12:01:27

一、高階函數

JavaScript 中的高階函數是一種接受函數作為輸入或返回函數作為輸出的函數。它們提供了靈活的方式來處理常式,並允許把函數作為引數或返回值傳遞。它們是函數語言程式設計的重要組成部分,並且可以提高程式碼的可讀性和可維護性。

高階函數的一個常見用法是對陣列進行操作,例如使用 map()reduce()filter()。這些函數允許您在陣列上應用自定義的函數,並對陣列的每個元素執行操作。

另一個常見的高階函數是回撥函數。回撥函數是一種被傳遞到另一個函數中的函數,並在某些事件發生時被呼叫。它們允許您建立程式碼,該程式碼在事件發生時自動執行。

另外,高階函數還可以用於建立抽象概念,例如柯里化組合管道。柯里化是一種將多個引數的函數轉換為一系列接受單個引數的函數的技術。組合是將多個函陣列合成一個新函數的技術。管道是一種通過將函數的輸出作為下一個函數的輸入來連結多個函數的技術。

高階函數也可以與閉包結合使用。閉包是一種函數,它參照了定義它的作用域之外的變數。這使得您可以在函數外存取函數內部的變數,並將變數儲存在記憶體中以供以後使用。

高階函數是 JavaScript 程式設計的重要概念,具有很多用途,並且可以提高程式碼的複雜性。學習如何使用高階函數,並將其與其他技術結合起來,可以使您的程式碼更加強大和高效。

 

一個常見的 JavaScript 高階函數範例是 Array.prototype.map()

const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(function(number) {
  return number * 2;
});
console.log(doubledNumbers); // [2, 4, 6, 8, 10]

在這個例子中,我們建立了一個陣列,然後使用 map() 函數對陣列中的每個元素進行操作。我們傳遞了一個回撥函數,該回撥函數接受一個數位,並返回該數位的兩倍。

另一個常見的高階函數範例是 Array.prototype.reduce()

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce(function(total, number) {
  return total + number;
}, 0);
console.log(sum); // 15

在這個例子中,我們使用 reduce() 函數對陣列中的所有元素進行操作。我們傳遞了一個回撥函數,該回撥函數接受當前的總和和數位,並返回新的總和。

這些範例說明了高階函數的強大功能,以及如何將其與其他技術(例如回撥函數)結合起來,以實現複雜的操作。

二、使用高階函數實現函數柯里化

柯里化是一種高階函數的技術,可以將多個引數的函數轉換為只有一個引數的函數。這可以使我們在需要的時候再傳遞其他引數,並逐步構建出完整的函數。

以下是 JavaScript 使用高階函數實現柯里化的範例:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(null, args);
    } else {
      return function(...args2) {
        return curried.apply(null, args.concat(args2));
      };
    }
  };
}

function add(a, b, c) {
  return a + b + c;
}

const curriedAdd = curry(add);
const add5 = curriedAdd(5);
console.log(add5(10, 15)); // 30

在這個例子中,我們建立了一個 curry() 函數,該函數接受一個函數作為引數,並返回一個新函數。該新函數使用 apply() 方法應用所有引數,如果傳遞的引數數量不夠,則返回一個新的函數,該函數將傳遞的引數與當前的引數合併。

然後,我們使用 curry() 函數對 add() 函數進行柯里化,並建立了一個只接受一個引數的函數,該引數為 5。我們可以使用此函數來逐步構建出完整的函數,並使用最後兩個引數計算結果。

三、使用高階函數實現組合函數

組合函數是一種將多個函數結合起來以建立新函數的技術。在 JavaScript 中,可以使用高階函數實現組合函數。

以下是使用高階函數實現組合函數的範例:

function compose(f, g) {
  return function(x) {
    return f(g(x));
  };
}

function double(x) {
  return x * 2;
}

function add(x) {
  return x + 1;
}

const composed = compose(add, double);
console.log(composed(3)); // 7

在這個例子中,我們建立了一個 compose() 函數,該函數接受任意數量的函數作為引數,並返回一個新函數。

然後,我們使用 compose() 函數將 double()add() 函陣列合在一起,並使用組合函數對數位 3 進行計算。因此,先呼叫 double(3),再呼叫 add(6),最後得到結果 7。

 

以下是另一種使用高階函數實現組合函數的範例:

function compose(...fns) {
  return function(arg) {
    return fns.reduceRight((result, fn) => fn(result), arg);
  };
}

function double(x) {
  return x * 2;
}

function add(x) {
  return x + 1;
}

const composed = compose(double, add);
console.log(composed(3)); // 8

在這個例子中,我們建立了一個 compose() 函數,該函數接受任意數量的函數作為引數,並返回一個新函數。該新函數使用 reduceRight() 函數對所有函數進行組合,並對給定的引數進行計算。

然後,我們使用 compose() 函數將 double()add() 函陣列合在一起,並使用組合函數對數位 3 進行計算。因此,先呼叫 add(3),再呼叫 double(4),最後得到結果 8。

四、使用高階函數實現管道

 管道是一種將多個函數連線起來以進行順序計算的技術。在 JavaScript 中,可以使用高階函數實現管道。

以下是使用高階函數實現管道的範例:

function pipe(...fns) {
  return function(arg) {
    return fns.reduce((result, fn) => fn(result), arg);
  };
}

function double(x) {
  return x * 2;
}

function add(x) {
  return x + 1;
}

const piped = pipe(add, double);
console.log(piped(3)); // 8

在這個例子中,我們建立了一個 pipe() 函數,該函數接受任意數量的函數作為引數,並返回一個新函數。該新函數使用 reduce() 函數對所有函數進行管道,並對給定的引數進行計算。

然後,我們使用 pipe() 函數將 add()double() 函數管道在一起,並使用管道函數對數位 3 進行計算。因此,先呼叫 add(3),再呼叫 double(4),最後得到結果 8。

五、組合函數和管道的區別

管道和組合函數都是高階函數的應用,但是它們有著明顯的不同:

  1. 實現方式:管道是通過將多個函數連線起來,依次對資料進行處理,而組合函數則是通過將多個函陣列合成一個函數。

  2. 計算順序:管道函數的計算順序是從左到右而組合函數的計算順序是從右到左

  3. 結構:管道函數的結構是一維的,每一步的結果都是下一步的輸入;而組合函數的結構是二維的,一個函數的結果可以作為另一個函數的輸入。

因此,管道和組合函數都是高階函數的重要應用,在不同的場景中使用它們都有著獨特的優勢。