chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

[JS] Higher-order functions. Jak wydajnie pisać kod aplikacji webowych?

Ta wersja
blog.piotrnalepa.pl/2013/04/10/js-higher-order-functions-jak-wydajnie-pisac-kod-aplikacji-webowych
Opublikowano
Autor
, Staff Software Engineer
Kategoria
JavaScript
Uwagi
Napisz do mnie · Napisz na X

Ten wpis ma 13 lat. Od tego czasu przeglądarki i narzędzia mogły się zmienić, więc zanim użyjesz kodu, sprawdź go z aktualną dokumentacją.

W języku skyptowym Javascript możemy tworzyć funkcje za pomocą wielu sposobów. Można utworzyć funkcje anonimowe, nazwane czy też samowykonywujące się. Każda z nich ma swoje wady i zalety, ale co ciekawsze istnieją też funkcje wyższego rzędu (tzw. higher-order functions). Co to jest za twór?

Sekcja 1Higher-order functions - trochę teorii

Funkcja wyższego rzędzu jest to funkcja, która przyjmuje funkcję jako parametr funkcji oraz jako swój wynik zwraca inną funkcję. To tyle i aż tyle. Z tego typu funkcjami spotykamy się na codzień bardzo często nie mając o tym pojęcia, np. w bibliotece jQuery.

Zapewne to dalej brzmi tajemniczo, dlatego się postaram to nieco rozjasnić za pomocą przykładu.

Sekcja 2Funkcja wyższego rzędu - przykład użycia

Przykład, będzie funkcją której zadaniem będzie zwrócenie wszystkich wartości wybranej własności w danym zbiorze, to znaczy, będziemy mieć tablicę użytkowników i będziemy chcieli wymienić ich z imienia.

Przykład 1JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
(function (window, document) { //#1
  var users = [ //#2
    { id: 1, name: 'Adam', age: 23},
    { id: 2, name: 'Marek', age: 55},
    { id: 3, name: 'Piotr', age: 20},
    { id: 4, name: 'Antoni', age: 10}
  ];
 
  var by = function (property) { //#3
    return function (a, b) {
      if (a[property] < b[property]) {
        return -1;
      } else if (a[property] === b[property]) {
        return 0;
      } else {
        return 1;
      }
    }
  };
 
  users.sort(by('age')); //#4
 
  var usersConcat = users.map((function(property) { //#5
    return function(user) { 
      return user[property]; 
    };
  }('name'))).join(', ');
 
  var resultContainer = document.getElementsByClassName('result')[0]; //#6
 
  resultContainer.innerHTML = usersConcat; //#7
} (this.window, this.window.document));

Korzystam tutaj z czystego Javascript, bez użycia biblioteki jQuery.
Analizując powyższy kod widzimy:

  1. Samowykonującą się funkcję, która jest "odpalana" w momencie gdy strona się załaduje;
  2. Tablicę obiektów;
  3. Funkcję by(), która jako swój parametr przyjmuje nazwę własności obiektu. Jest to przykład "higher-order function" - funkcja zwraca funkcję i jako swoje parametry przyjmuje wartości zwracane przez funkcję zagnieżdżoną głębiej.
    W tym przypadku, funkcja zagnieżdżona porównuje wartosci atrybutów między kolejnymi obiektami i zwraca ich kolejność. Należy pamiętać, że parametrami funkcji zagnieżdżonej są wartości przyjmowane przez funkcję zagnieżdżoną. Takie podejście wprowadza nas na nowy poziom abstrakcji w pisaniu kodu. Podobne podejście można wykorzystać w innych językach programowania.
  4. Wywołujemy funkcję sort(), która jest natywną funkcją JS, a jej parametrem jest funkcja;
  5. Tworzymy ciąg z wartosciami własnosci name, jest to kolejny przykład na wykorzystanie funkcji wyższego rzędu. Funkcja map ma za zadanie pomapować obiekty wg zdefiniowanych reguł. Przyjmuje funkcję jako swój parametr. Funkcja ta, staje się funkcją zagnieżdżoną, która zwraca wybrane wartości własnosci. Map() jest swoistym substytutem funkcji forEach(), ale dzięki funkcji map() możemy uniknąć tworzenia nadmiarowych zmiennych.
    Na koniec za pomocą join() łączymy wartości z tablicy w jeden ciąg słów przedzielonych przecinkiem;
  6. Szukamy pierwszego elementu w drzewie DOM posiadającego klasę result;
  7. Na koniec, wstawiamy wcześniej przygotowany ciąg imion do wybranego elementu na stronie (posiadającego klasę result).

Sekcja 3Kiedy korzystać z funkcji wyższego rzędu?

Bardzo często z funkcji wyższego rzędu można korzystać w miejscach, gdzie jest wymagany callback, np. w wywołaniach AJAX tworzonych za pomocą biblioteki jQuery.
Higher-order functions występują często przy okazji wykorzystania natywnych funkcji JS dla tablic, takich jak: map(), reduce() czy filter(). Funkcje te przyjmują inne funkcje jako swoje parametry.

Sekcja 4Zalety wykorzystania funkcji wyższego rzędu

  • redukcja używanych zmiennych,
  • uproszczenie kodu,
  • tworzenie ładnych "jednolinijkowców" (#4 z listingu powyżej).

Sekcja 5Podsumowanie

Tym wpisem chciałem przybliżyć tematykę tworzenia funkcji wyższego rzędu, które pozwalają na uproszczenie kodu i redukcję zmiennych, co pozytywnie wpływa na wydajność aplikacji webowych.
Zdaję sobie sprawę, że dla osoby nie mającej do tej pory styczności z tego typu tworami JS może zająć trochę czasu jego dobre zrozumienie, lecz warto dać temu szansę.

Warto zajrzeć w te źródła: źródło1, źródło2

Udostępnij
Uwagi

O autorze

Staff Software Engineer

Piszę na tym blogu od 2009 roku, a strony i aplikacje webowe tworzę zawodowo od 14 lat. Obecnie w Bishop Fox prowadzę frontend platformy Cosmos, od samego początku projektu. Wcześniej pracowałem m.in. w OLX, KUDO, Auto1 i eZ Systems. Piszę tu o tym, czego nauczyłem się w praktyce: o JavaScripcie, TypeScripcie, Reakcie, CSS-ie i architekturze frontendu. Występowałem też jako prelegent na konferencjach w Polsce i Europie. Masz pytanie albo pomysł na wpis? Daj znać!