chevron-left chevron-right

[JS] Prawda czy fałsz? Sztuczki z operatorami bitowymi i logicznymi w języku JavaScript

Tworząc aplikacje internetowe, czasami pojawia się potrzeba dokonania mikro optymalizacji w szybkości działania funkcji zaimplementowanych w aplikacjach. Dzięki nim, można osiągnąć lepszą wydajność aplikacji, a także większą stabilność działania. Jedną z możliwości jakie daje nam język JavaScript (i nie tylko) jest stosowanie operatorów bitowych i operatorów logicznych, które będą sprawdzały wartości zmiennych, odpowiednio je przekształcały do pożądanej przez nas formy czy też zastępowały pętle.

Zaokrąglanie liczb za pomocą operatora NOT

W przypadku, gdy istnieje potrzeba zaokrąglania liczby w dół web developerzy stosują Math.floor(x), podczas gdy istnieją co najmniej 3 szybsze sposoby, aby osiągnąć ten sam efekt:

  • y = ~~x;,
  • y = x | 0;,
  • y = x >> 0;.

Wszystkie te 3 sposoby, są szybszymi zamiennikami popularnej metody do zaokrąglania w dół.

Sprawdzanie czy liczba jest parzysta?

Tworząc różnego listingi lub budując tabelę z dynamicznie generowaną treścią (dodawanie/odejmowanie wierszy) bardzo często stosowane są klasy definiujące czy dany wiersz jest parzysty czy nieparzysty. W takich sytuacjach często są używane sprawdzenia czy kolejna liczba jest modułem z 2 - y = x % 2; i tutaj też jest zamiennik, który jest szybszy: y = (x & 1);. Zapis ten zwraca true, jeśli wartość jest nieparzysta.

Zwracanie wartości typu boolowskiego/logicznego

Czasami web developerzy operują na zmiennych true/false i to jest w porządku. Lecz ze względu na to, że istnieją różne postaci typu fałszywego, takie jak:

  • false,
  • NaN,
  • undefined,
  • null,
  • '' (pusty string),
  • 0.

To nie mogą być one używane jako wartości właściwosci obiektów, które w założeniach przyjmują tylko wartości true lub false. W takich sytuacjach można wykorzystać zapis: y = !!x;. Gdyby x przyjął wartość undefined, to ten zapis zwróci wartość false, a w przypadku gdy wartość zmiennej będzie określona lub nie będzie typu fałszywego to będzie zwracała true, np. gdy zastosujemy taki zapis if (!!$('body').length) ....

Działania warunkowe - if

Działania warunkowe w językach programowania są widokiem tak powszechnym, że z reguły nie sprawiają żadnych problemów z ich odczytaniem. Czasami można natknąć się na tajemnicze zapisy, które zachowują się jak warunki, ale na takie nie wyglądają. Są to skrócone zapisy warunku if lub inaczej wywołania warunkowe.

1
2
3
if (true) {
  wykonaj();
}

Standardowy warunku if można zastąpić zapisem: true && wykonaj();. Jest to zapis krótszy i może być wykorzystywany, gdy zależy będzie Ci zależało na maksymalnym zmniejszeniu wagi pliku.

Inne przykłady wykorzystania wywołań warunkowych są następujące:

1
2
3
if (!true) {
  wykonaj();
}

Powyższy zapis można zastąpić następującym kodem: true || wykonaj();. Czyli, jeśli wartość nie jest prawdziwa/nie istnieje to wykonaj funkcję.

Do tej pory wykonywaliśmy działania warunkowe, które wywołują się tylko w jednym przypadku. Lecz można też utworzyć skrótową wersję warunku if else za pomocą zapisu: x && wykonaj() || nieWykonuj();. Ten sam warunek można zapisać jeszcze inaczej: x ? wykonaj() : nieWykonuj();

Jednym z przykładów z życia wziętych może być następujący kod:

1
2
3
4
5
6
7
8
var element = $('.element');
$('.element').hasClass('focus') && (function () {
  element.sibling().removeClass('active');
  $('#activity').text('Element ma klasę .focus');
  setTimeout(function () {
    wykonajAnimacje(element);
  }, 1000);
});

Jeśli element ma klasę focus, to wykonaj zawartość anonimowej funkcji. Jest to proste i efektywne rozwiązanie.

Funkcje z parametrami o wartościach domyślnych

W języku JavaScript w definicji funkcji nie możemy definiować wartości domyślnych parametrów, tak jak to ma miejsce chociażby w języku PHP. Na szczęście, istnieje inne wyjście - przypisania warunkowe.

1
2
3
4
function (active) {
  var isActive = active || false;
  ...
}

Wyżej wymieniona funkcja przyjmuje jeden parametr: active, jeśli jej wartość jest zdefiniowana, to zmienna isActive przyjmie wartość true, a jeśli nie jest zdefiniowana to zmienna przyjmie wartość domyślną (zdefiniowaną przez programistę).

Podsumowanie

Wyżej wymienione przykłady to tylko część możliwości jakie daje nam operowanie na wartościach zmiennych za pomocą operatorów bitowych i logicznych. W części przypadków znacząco to przyspiesza działanie aplikacji, a w części przypadków pozwala na redukcję wagi pliku skryptu.
Takie rozwiązania są bardzo użyteczne, ale bardzo często jest to osiągane zmniejszeniem czytelności kodu.
W większości przypadków, czytelność kodu w wersji rozwojowej jest więcej warta niż mikro optymalizacje. Dzięki czytelności kodu możemy zaoszczędzić czas poświęcony na rozwiązywanie problemów z kodem lub poświęcony na wprowadzanie nowych funkcjonalności. Warto jednak mieć na uwadze sposoby na optymalizację kodu wymienione wyżej, ponieważ mogą się przydać w krytycznych sytuacjach.