Menu

Koercja typów w JavaScript: konwersje niejawne i jawne

Jak JavaScript zamienia wartości między typami: niejawne reguły, na których ludzie się potykają, jawne konwersje, które warto wybierać, i kiedy działa każda z nich.

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

Dwa rodzaje koercji

JavaScript luźno podchodzi do typów. Gdy operator dostaje wartość „złego” typu, język nie rzuca błędu, tylko ją konwertuje. Taka konwersja to koercja (coercion) i występuje w dwóch odmianach:

  • Jawna: sam o nią prosisz, Number("42"), String(99), Boolean(value).
  • Niejawna: uruchamia ją operator, choć nie napisałeś konwersji, "5" - 2, "" == 0, if (value).

Obie ostatecznie korzystają z tych samych reguł konwersji. Różnica polega na tym, czy o konwersji decydujesz ty, czy język. Niemal każdy mylący wynik w JavaScript, "5" + 1 === "51", [] == false, null == undefined, bierze się z niejawnej koercji, która zaskakuje cię znienacka.

Model myślowy: jeśli piszesz Number(...) albo String(...), wiesz, o co prosisz. Jeśli nie, każdy operator ma własne zdanie na temat tego, co zrobić, i właśnie w tych zdaniach mieszkają błędy.

Trzy typy docelowe

Koercja zawsze konwertuje do jednego z trzech typów prymitywnych: string, number albo boolean. (Jest też czwarty, bigint, ale inne typy nigdy nie są do niego automatycznie konwertowane). Cała reszta reguł wynika z tego, do którego typu dąży dany operator.

Koercja do stringa jest najbardziej wyrozumiała: każda wartość ma postać tekstową. Zauważ, że obiekty zamieniają się na mało pomocne "[object Object]", dlatego logowanie obiektu doklejonego do stringa ("user: " + user) prawie nigdy nie pokazuje tego, czego chcesz. Zamiast tego użyj JSON.stringify albo template literals z konkretnymi polami.

Koercja do liczby

Koercja do liczby jest bardziej rygorystyczna. Stringi muszą naprawdę wyglądać jak liczba, w przeciwnym razie dostajesz NaN:

Niespodzianki oznaczone w nawiasach warto zapamiętać:

  • Pusty string i string z samych spacji dają 0, a nie NaN.
  • null daje 0, ale undefined daje NaN.
  • Pusta tablica daje 0, tablica z jednym elementem jest konwertowana jak ten element, a tablica z wieloma elementami daje NaN.

Jeśli chcesz wyciągnąć liczbę ze stringa z dodatkowymi znakami, użyj parseInt albo parseFloat zamiast Number:

Zawsze przekazuj do parseInt podstawę systemu (10). Bez niej stringi zaczynające się od "0x" są parsowane szesnastkowo, a rzadko o to ci chodzi.

Koercja do boolean

Koercja do boolean jest najprostsza z trzech. Krótka lista wartości zamienia się na false, a wszystko inne na true.

Wartości falsy to:

  • false
  • 0, -0, 0n
  • "" (pusty string)
  • null
  • undefined
  • NaN

To wszystko. Każda inna wartość, w tym "false", "0", [] i {}, jest truthy.

Wyniki dla pustej tablicy i pustego obiektu zaskakują osoby przychodzące z Pythona, gdzie puste kolekcje są falsy. W JavaScript są truthy: jeśli chcesz sprawdzić, czy tablica jest pusta, sprawdź jawnie arr.length === 0.

Koercja do boolean zachodzi zawsze, gdy wartość pojawia się tam, gdzie oczekiwany jest boolean: if (...), while (...), operator trójargumentowy ? : oraz operatory logiczne &&, ||, !.

Operator + to przypadek szczególny

Większość operatorów arytmetycznych wymusza zamianę operandów na liczby. + działa inaczej: jeśli którakolwiek strona jest stringiem, + łączy stringi. W przeciwnym razie dodaje liczby.

Obliczanie przebiega od lewej do prawej. 1 + 2 + "3" najpierw liczy 1 + 2 = 3, a potem 3 + "3" = "33". Natomiast "1" + 2 + 3 od początku jest stringiem i już nim pozostaje: "12", potem "123".

Dlatego budowanie stringów przez + jest kruche. Template literals nie mają tego problemu:

Template literal oblicza count + 1 jako osobne wyrażenie liczbowe, a dopiero potem wstawia wynik. Żadnej niespodziewanej koercji.

Wybieraj jawne konwersje

Gdy musisz zmienić typ, powiedz to wprost. Kosztuje to kilka znaków, a następnej osobie czytającej kod usuwa wszelkie wątpliwości:

Podobnie z wartościami logicznymi. !!value działa i jest popularne, ale Boolean(value) mówi dokładnie, co robi:

Rozsądna zasada: w logice aplikacji używaj jawnych konwersji, a krótkie formy (+x, !!x) zostaw na miejsca, gdzie liczy się zwięzłość, a intencja jest oczywista z kontekstu.

Operator == mocno polega na koercji

Operatory równości to największe źródło niespodzianek związanych z koercją. == konwertuje przed porównaniem, === nie.

Każde true powyżej to wynik wieloetapowego łańcucha koercji, którego większość programistów nie wyrecytuje z pamięci. I w tym problem: kod, który działa przypadkiem, to kod, który później się zepsuje. Pełne reguły równości omówimy na następnej stronie. Na razie zapamiętaj: domyślnie używaj ===, a po == sięgaj tylko w konkretnym idiomie x == null (który łapie zarówno null, jak i undefined).

Wszystko razem

Przykład pokazujący, gdzie koercja pomaga, a gdzie szkodzi:

Zwróć uwagę na drugie wywołanie. Number("") zwraca 0, a nie NaN, więc parsePrice("") zwraca 0, czego użytkownik tej funkcji raczej by nie chciał. Jeśli puste dane mają być odrzucane, dodaj jawne sprawdzenie:

Wiedza, które wartości zamieniają się na 0, a które na NaN, to właśnie to, co chroni cię przed subtelnym błędem w dalszej części kodu.

Co warto zapamiętać

  • Koercja konwertuje do string, number albo boolean, zależnie od operatora.
  • + z jakimkolwiek stringiem staje się łączeniem stringów, a każdy inny operator arytmetyczny konwertuje do liczby.
  • Wartości falsy to stała, krótka lista: zapamiętaj ją. Wszystko inne jest truthy, w tym [] i {}.
  • Number("") to 0, Number([]) to 0, Number(null) to 0, ale Number(undefined) to NaN. To pojawia się w prawdziwych błędach.
  • Wybieraj Number(x), String(x), Boolean(x) zamiast sprytnych niejawnych sztuczek. Przyszły ty będzie ci wdzięczny.

Dalej: operatory równości

Wszystko, co koercja robi w porównaniach, dzieje się wewnątrz ==. Następna strona omawia ==, === i Object.is, jedyny idiom, w którym == nadal się przydaje, i powód, dla którego lintery domyślnie oznaczają luźną formę.

Najczęściej zadawane pytania

Czym jest koercja typów w JavaScript?

Koercja typów (type coercion) to automatyczna zamiana wartości z jednego typu na inny: liczby w string, stringa w liczbę albo czegokolwiek w boolean. Dzieje się niejawnie, gdy operatory takie jak +, == czy if dostają wartość innego typu, niż oczekują, i jawnie, gdy sam wywołujesz Number(x), String(x) albo Boolean(x).

Czym różni się koercja niejawna od jawnej?

Koercja jawna to celowe wywołanie funkcji konwertującej: Number("42"), String(99), Boolean(value). Koercja niejawna to konwersja uruchamiana przez operator za twoimi plecami: "5" - 2 daje 3, a "5" + 2 daje "52". Jawna jest czytelna i przewidywalna, niejawna stoi za większością błędów typu „skąd tu NaN”.

Jak zamienić string na liczbę w JavaScript?

Użyj Number("42") do ścisłej konwersji (zwraca NaN, jeśli string nie jest poprawną liczbą) albo parseInt("42px", 10) / parseFloat("3.14em"), jeśli chcesz odczytać liczbę z początku mniej uporządkowanego stringa. Jednoargumentowy operator + (+"42") działa tak samo jak Number(), ale łatwiej go przeoczyć przy przeglądaniu kodu.

Dlaczego [] + [] zwraca pusty string?

Operator + nie ma sensownej operacji liczbowej dla dwóch tablic, więc JavaScript zamienia obie na stringi. Tablice zamieniają się na string przez połączenie elementów przecinkami, a pusta tablica daje "". Tak więc [] + [] staje się "" + "", czyli "". To zabawna sztuczka i dobry powód, żeby nigdy nie polegać na + z wartościami nieprymitywnymi.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ