Menu

Operatory w JavaScript: przewodnik z przykładami

Operatory, które JavaScript daje do liczenia, porównywania wartości, łączenia wartości logicznych i przypisywania, razem z pułapkami, które naprawdę dają się we znaki.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Operatory to sposób, w jaki wyrażenia wykonują pracę

Każda nietrywialna linijka JavaScript jest zbudowana z operatorów: symboli, które biorą jedną lub dwie wartości i tworzą nową. + dodaje, === porównuje, && łączy wartości logiczne, ? : wybiera jedną z dwóch wartości. Większość znasz z innych języków, ale kilka ma specyficzne dla JavaScript dziwactwa, które warto poznać od razu.

Przejdziemy przez nie według kategorii, a na koniec zostawimy te, po które sięgasz najrzadziej, ale które mają znaczenie, gdy są potrzebne.

Operatory arytmetyczne

Podstawowe działają tak, jak się spodziewasz:

Kilka rzeczy, na które warto zwrócić uwagę:

  • / zawsze dzieli zmiennoprzecinkowo. 7 / 2 to 3.5, a nie 3. Jeśli chcesz liczbę całkowitą, użyj Math.floor(7 / 2) albo Math.trunc(7 / 2).
  • % to reszta z dzielenia, a nie matematyczne modulo. Zachowuje znak lewego operandu: -7 % 3 to -1, a nie 2.
  • + jest przeciążony. Jeśli którakolwiek strona jest stringiem, łączy zamiast dodawać: "3" + 1 to "31". Więcej o tym za chwilę.

Inkrementacja i dekrementacja

Różnica między count++ a ++count ma znaczenie tylko wtedy, gdy używasz wartości wyrażenia w tej samej linijce. Jako osobna instrukcja oba robią to samo. Większość przewodników stylu woli count += 1, bo jest jaśniejsze.

Operator + ma dwie osobowości

Na tym każdy potyka się przynajmniej raz:

Jeśli którykolwiek operand jest stringiem, + staje się łączeniem stringów i zamienia drugą stronę na string. Wszystkie inne operatory arytmetyczne działają odwrotnie: zamieniają stringi na liczby:

Wniosek: gdy budujesz stringi, wybieraj template literals (`price: ${5}`). Gdy liczysz, upewnij się, że dane wejściowe naprawdę są liczbami: Number(x) albo parseInt(x, 10) konwertuje jawnie.

Operatory porównania

Porównania zwracają wartości logiczne. Są dwie odmiany: ścisła i luźna.

=== i !== są ścisłe: ta sama wartość i ten sam typ. == i != przed porównaniem konwertują typy, co prowadzi do niespodzianek, takich jak null == undefined równe true czy [] == false równe true. Domyślnie używaj === i !==. Jedyny popularny wyjątek to x == null, wygodny skrót na pytanie "czy x to null albo undefined?"

Operatory porządku działają na liczbach tak, jak się spodziewasz, a na stringach alfabetycznie:

Porównywanie stringów opiera się na kodach znaków, więc rozróżnia wielkość liter. Jeśli potrzebujesz sortowania przyjaznego ludziom, użyj String.prototype.localeCompare.

Operatory logiczne

&& (AND), || (OR) i ! (NOT) łączą wartości logiczne, ale są ciekawsze, niż sugerowałaby czysta algebra Boole'a.

Haczyk: && i || nie zwracają true ani false. Zwracają jeden ze swoich operandów. && zwraca pierwszą wartość falsy albo ostatnią, jeśli wszystkie są truthy. || zwraca pierwszą wartość truthy albo ostatnią, jeśli wszystkie są falsy.

Dlatego widać wzorce takie jak const displayName = user.name || "Guest": weź pierwszą rzecz, która nie jest pusta. To zwięzłe, ale uważaj: || traktuje 0, "" i false jako powód do użycia wartości zapasowej. Jeśli to u ciebie poprawne wartości, użyj zamiast tego ?? (niżej).

Oba operatory działają też na skróty (short-circuit): jeśli lewa strona już przesądza o wyniku, prawa w ogóle się nie wykonuje.

Operator nullish coalescing ??

?? działa jak ||, ale reaguje tylko na null lub undefined, a nie na 0, "" czy false.

Używaj ??, gdy poprawna wartość może być falsy: liczniki, puste stringi, jawne false. Używaj ||, gdy każda wartość falsy ma oznaczać "brak". We współczesnym kodzie ?? to bezpieczniejszy wybór domyślny dla opcjonalnych wartości z wartością domyślną.

Operatory przypisania

= przypisuje. Formy złożone łączą przypisanie z innym operatorem:

Są też logiczne operatory przypisania: ||=, &&= i ??=, które przypisują tylko wtedy, gdy obecna wartość spełnia warunek:

Przydają się do uzupełniania wartości domyślnych bez rozwlekłych instrukcji if.

Operator ternarny

condition ? a : b to wersja if/else w postaci wyrażenia. Zwraca a, gdy warunek jest truthy, a w przeciwnym razie b:

Operator ternarny świetnie sprawdza się przy krótkim wybieraniu wartości. Staje się nieczytelny, gdy tylko zaczniesz go zagnieżdżać: jeśli piszesz a ? b : c ? d : e, sięgnij po if/else albo obiekt z mapowaniem.

typeof i instanceof

typeof zwraca string opisujący typ operandu:

Dwie pułapki warte zapamiętania: typeof null to "object" (błąd z 1995 roku, który jest już na stałe), a tablice też zgłaszają "object". Do tablic używaj Array.isArray(x), a do null x === null.

instanceof sprawdza, czy obiekt został utworzony z konkretnego konstruktora:

Spread i rest używają tego samego ...

... zobaczysz w dwóch miejscach. Jako spread rozkłada obiekt iterowalny na pojedyncze elementy:

Jako rest zbiera wiele wartości w jedną tablicę, zwykle w parametrach funkcji albo w destrukturyzacji:

Ta sama składnia, odwrotne zadania. Spread rozpakowuje, rest zbiera. O tym, który jest który, decyduje kontekst: w wywołaniu lub literale rozkłada, w liście parametrów lub wzorcu destrukturyzacji zbiera.

Priorytet operatorów (w razie wątpliwości dodaj nawiasy)

Operatory mają priorytet, który decyduje, który wykona się pierwszy, gdy je mieszasz. Mnożenie wygrywa z dodawaniem, porównanie z operatorami logicznymi i tak dalej:

Pełna tabela jest długa i nikt nie pamięta jej całej. Prosty nawyk pokrywa 99% przypadków: gdy mieszasz operatory i nie masz pewności co do kolejności, dodaj nawiasy. Kod czyta się lepiej i nie zależy od pamięci czytelnika.

Operatory bitowe (rzadko to, czego chcesz)

Dla kompletności: &, |, ^, ~, <<, >> i >>> działają na binarnej reprezentacji liczb całkowitych. Zobaczysz je w kodzie graficznym, niskopoziomowych protokołach i w API, które używają masek bitowych jako flag.

Popularna, ale wątpliwa sztuczka: n | 0 obcina liczbę do 32-bitowej liczby całkowitej i kiedyś nadużywano tego jako szybszego Math.trunc. Nie rób tego: Math.trunc jest czytelniejsze i działa dla liczb spoza zakresu 32 bitów.

Dalej: if/else

Operatory tworzą wartości, a if/else używa tych wartości, żeby wybrać gałąź kodu do wykonania. Większość tego, co zrobisz z powyższymi operatorami porównania i logicznymi, to przekazywanie ich wyników do instrukcji warunkowych, i właśnie o tym jest następna strona.

Najczęściej zadawane pytania

Jakie są główne operatory w JavaScript?

JavaScript ma operatory arytmetyczne (+, -, *, /, %, **), porównania (===, !==, <, >), logiczne (&&, ||, !), przypisania (=, +=, -=) i kilka specjalnych, takich jak ternarny ? :, typeof i nullish coalescing ??. To podstawowe klocki wyrażeń i sterowania przepływem programu.

Jaka jest różnica między == a === w JavaScript?

=== sprawdza, czy zgadza się i wartość, i typ. == przed porównaniem konwertuje typy, więc 0 == "0" daje true, ale 0 === "0" daje false. Domyślnie używaj ===: reguły konwersji == są na tyle zawiłe, że powodują błędy, których nie wyłapiesz w code review.

Co robi operator ternarny w JavaScript?

condition ? a : b to jednolinijkowy if/else, który zwraca wartość. Jeśli condition jest truthy, wynikiem jest a, w przeciwnym razie b. Przydaje się do krótkich wyrażeń warunkowych, takich jak const label = count === 1 ? 'item' : 'items', ale zagnieżdżone operatory ternarne szybko stają się nieczytelne.

Kiedy używać ?? zamiast ||?

|| sięga po wartość zapasową przy każdej wartości falsy, także 0, "" i false. ?? robi to tylko przy null lub undefined. Jeśli chcesz, żeby count ?? 10 zachowało poprawne 0, użyj ??. Jeśli naprawdę każda wartość falsy ma uruchamiać wartość zapasową, zostań przy ||.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ