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 / 2to3.5, a nie3. Jeśli chcesz liczbę całkowitą, użyjMath.floor(7 / 2)alboMath.trunc(7 / 2).%to reszta z dzielenia, a nie matematyczne modulo. Zachowuje znak lewego operandu:-7 % 3to-1, a nie2.+jest przeciążony. Jeśli którakolwiek strona jest stringiem, łączy zamiast dodawać:"3" + 1to"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 ||.