JavaScript — idea programowania funkcjonalnego.

Mar 21 2023
Programowanie funkcyjne to paradygmat programowania, który kładzie nacisk na pisanie programów przy użyciu czystych funkcji, które nie mają skutków ubocznych i zawsze zwracają to samo wyjście przy tym samym wejściu. JavaScript to wieloparadygmatowy język, który obsługuje programowanie funkcyjne, wraz z innymi paradygmatami programowania, takimi jak programowanie obiektowe i programowanie imperatywne.
Zdjęcie Growtika na Unsplash

Programowanie funkcyjne to paradygmat programowania, który kładzie nacisk na pisanie programów przy użyciu czystych funkcji, które nie mają skutków ubocznych i zawsze zwracają to samo wyjście przy tym samym wejściu. JavaScript to wieloparadygmatowy język, który obsługuje programowanie funkcyjne, wraz z innymi paradygmatami programowania, takimi jak programowanie obiektowe i programowanie imperatywne.

Czyste funkcje są ważne w programowaniu funkcjonalnym, ponieważ są deterministyczne i wolne od skutków ubocznych, co ułatwia ich rozumowanie, testowanie i debugowanie. Efekt uboczny to każdy obserwowalny efekt lub interakcja, która występuje poza zakresem funkcji lub metody w wyniku jej wykonania. Może to obejmować modyfikowanie zmiennej lub obiektu poza zakresem funkcji, zapisywanie do pliku lub wykonywanie dowolnej operacji we/wy.

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

Jako funkcje, które nie mają skutków ubocznych i dają ten sam wynik za każdym razem, gdy są wywoływane z tym samym wejściem, możemy je uelastycznić i zastosować te interesujące właściwości/techniki wymienione poniżej:

  • Idempotencja : może być przydatna w różnych scenariuszach, takich jak wywołania interfejsu API, aktualizacje baz danych lub aktualizacje interfejsu użytkownika, w których chcesz mieć pewność, że ta sama operacja nie zostanie wykonana wiele razy.
  • // Applying this function multiple times on the same number will always return the same result.
    
    Math.abs(-5) // Returns 5
    
    Math.abs(Math.abs(-5)) // Also returs 5
    
    

    // Example of currying
    function multiply(a) {
      return function(b) {
        return a*b;
      }
    }
    
    const multiplyBy2 = multiply(2);
    multiplyBy2(6);
    // Returns 6*2 = 12
    

  • Częściowe zastosowanie : Ta technika jest podobna do curry, ale jest nieco inna. Jest to dla nas sposób na częściowe zastosowanie funkcji, proces tworzenia funkcji o mniejszej liczbie parametrów.
  • // Example of Partial Application
    function multiply(a,b,c) {
      return a*b*c;
    }
    
    const multiplyBy2 = multiply.bind(null, 2);
    multiplyBy2(3,4)
    // Returns 2*3*4 = 24
    

  • Zapamiętywanie : Jest to technika używana do optymalizacji wydajności funkcji poprzez buforowanie wyników kosztownych wywołań funkcji i zwracanie buforowanego wyniku, gdy te same dane wejściowe wystąpią ponownie. W JavaScript zapamiętywanie można zaimplementować za pomocą domknięć i obiektów.
  • // Example of Memoization
    const memoizedOperation = (() => {
        let cache = {};
        return (n) => {
            if (n in cache) {
                console.log("Returning cached value: ");
                return cache[n];
            } else {
                console.log("Performing operation: ");
                cache[n] = n*10;
                return cache[n];
            }
        }
    })();
      
    console.log(memoizedOperation(4));
    console.log(memoizedOperation(4));
    console.log(memoizedOperation(5));
    
    /*
    Returns: 
      Performing operation: 
      40
      Returning cached value: 
      40
      Performing operation: 
      50
    */
    
    

  • Kompozycja: Jest to technika, która łączy wiele funkcji w jedną funkcję, w której dane wyjściowe jednej funkcji są przekazywane jako dane wejściowe do następnej funkcji. To pozwala nam tworzyć złożone funkcje poprzez komponowanie prostszych funkcji. Złożenie funkcji można uzyskać za pomocą compose()and pipe()(dostarczanych przez biblioteki takie jak Lodash czy Ramda) lub możemy też zdefiniować własne funkcje.
  • // Example of Composition by creating our own function
    const compose = (f,g) => (n) => f(g(n));
    const pipe = (f,g) => (n) => g(f(n));
    const multiplyBy2 = (n) => n * 2;
    const add2 = (n) => n + 2;
    const multiplyAndAddComp = compose(multiplyBy2, add2)
    const multiplyAndAddPipe = pipe(multiplyBy2, add2)
    
    console.log("Compose: ", multiplyAndAddComp(5));
    console.log("Pipe: ", multiplyAndAddPipe(5));
    
    /*Returns: 
      Compose:  14
      Pipe:  12
    */
    

Te funkcje są używane do tworzenia funkcji w JavaScript. Funkcja composeprzyjmuje dwie funkcje fi g, jako argumenty i zwraca nową funkcję, która jest złożeniem fi g. Zwrócona funkcja przyjmuje argument n, stosuje się gdo n, a następnie stosuje się fdo wyniku. Funkcja pipedziała podobnie do compose, ale stosuje funkcje w odwrotnej kolejności. Przyjmuje dwie funkcje fi g, jako argumenty i zwraca nową funkcję, która ma zastosowanie fdo wyniku g. Kod definiuje również dwie proste funkcje multiplyBy2i add2, które służą do komponowania funkcji. Następnie kod tworzy dwie nowe funkcje multiplyAndAddCompimultiplyAndAddPipe, tworząc odpowiednio funkcje multiplyBy2i add2przy użyciu funkcji composei pipe. Na koniec console.logwyciągi drukują wyniki stosowania multiplyAndAddCompi multiplyAndAddPipedo liczby 5.

multiplyAndAddCompnajpierw mnoży 5 przez 2, a następnie dodaje do tego 2, używając funkcji składania, więc wynikiem jest 12. multiplyAndAddPipenajpierw dodaje 2 do 5, a następnie mnoży wynik przez 2, używając funkcji składania, więc wynikiem jest 14.

Im mniej parametrów jest w funkcji, tym łatwiej jest używać tej funkcji z powyższymi technikami.

Wniosek

Ideą programowania funkcjonalnego jest oddzielenie danych i funkcji lub logiki, co czyni kod jasnym i zrozumiałym, rozszerzalnym, łatwym w utrzymaniu i, co ważniejsze, SUCHYM.