Menu

Operatory porównania w JavaScript: == vs === i Object.is

Jak działa porównywanie w JavaScript: równość ścisła i luźna, dziwactwa ==, zachowanie NaN i obiektów oraz kiedy sięgnąć po Object.is.

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

Dwa sposoby, by zapytać „czy to jest równe?”

JavaScript daje ci dwa operatory równości: === (ścisły) i == (luźny). Wyglądają niemal identycznie. Zachowują się zupełnie inaczej.

=== sprawdza, czy oba operandy mają ten sam typ i tę samą wartość. == najpierw konwertuje operandy do wspólnego typu, a dopiero potem porównuje. Ta konwersja, czyli koercja typów, stoi za większością złej sławy porównań w JavaScript.

Wersja skrócona: domyślnie używaj ===. Wersję długą warto przeczytać raz, żeby wiedzieć, z czego rezygnujesz.

Równość ścisła: to, czego prawdopodobnie chcesz

=== zwraca true tylko wtedy, gdy obie strony zgadzają się typem i wartością. Bez koercji, bez niespodzianek:

Jeśli typy się nie zgadzają, odpowiedź to od razu false. Jeśli się zgadzają, JavaScript porównuje wartości. Dla typów prostych to porównanie wartości, dla obiektów porównanie referencji (więcej o tym za chwilę).

!== to operator ścisłej nierówności i działa według tych samych zasad, tylko odwrotnie.

Równość luźna: koercja w przebraniu

== pozwala, by obie strony miały różne typy. Przed porównaniem odprawia taniec koercji, żeby je do siebie dopasować:

Dokładne zasady są w specyfikacji i nie są straszne, ale przypominanie ich sobie w trakcie debugowania to inna sprawa. To, że "0" == false daje true, zaskakuje nawet doświadczonych programistów. Podobnie [] == false (też true, bo tablica zamienia się w "", a to w 0).

Dlatego większość przewodników stylu, a także reguła eqeqeq w ESLint, każe domyślnie używać ===. Płacisz jednym znakiem więcej, a dostajesz zasady, które naprawdę da się zapamiętać.

Jedyny przydatny wzorzec z ==

Jest jeden idiom z luźną równością, który warto znać: x == null zwraca true, gdy x to null albo undefined, i false dla wszystkiego innego.

Ścisły odpowiednik to x === null || x === undefined, który działa, ale czyta się go z większym szumem. Wiele projektów dopuszcza == null jako jedyny uświęcony wyjątek. Wybierz regułę i stosuj ją konsekwentnie.

Obiekty porównuje się po referencji

W przypadku obiektów, tablic i funkcji zarówno ===, jak i == zadają to samo pytanie: „czy obie strony wskazują na ten sam obiekt w pamięci?”. A nie: „czy mają tę samą zawartość?”.

Dwa literały obiektów o identycznej zawartości to nadal dwa różne obiekty. Każdy przynajmniej raz się na tym potknie.

Żeby porównać po wartości, piszesz własną funkcję pomocniczą, używasz biblioteki (lodash.isequal) albo w przypadku prostych obiektów serializujesz je przez JSON.stringify:

JSON.stringify działa tylko dla prostych danych: pomija funkcje, undefined i symbole, a przy niektórych kształtach nie gwarantuje tej samej kolejności kluczy we wszystkich silnikach. To szybkie sprawdzenie, a nie ogólne rozwiązanie.

NaN nie jest równe niczemu

NaN („not a number”) to wartość, którą JavaScript zwraca, gdy operacja liczbowa nie ma sensownego wyniku: 0/0, Number("abc"), Math.sqrt(-1). Oba operatory równości zwracają false, gdy którakolwiek strona to NaN, także gdy obie strony to NaN:

Do wykrywania NaN używaj Number.isNaN(value). Nie używaj starszej globalnej funkcji isNaN: najpierw konwertuje ona argument, więc isNaN("hello") zwraca true, a to prawie nigdy nie jest to, czego chcesz.

Object.is: prawie ===, z dwiema poprawkami

Object.is(a, b) zachowuje się jak === poza dwoma przypadkami brzegowymi:

Zazwyczaj chcesz ===. Po Object.is sięgnij wtedy, gdy musisz traktować NaN jako równe samemu sobie albo odróżnić +0 od -0. Oba przypadki są rzadkie, ale czasem ważne w kodzie numerycznym i we wnętrzu frameworków (React używa Object.is do porównywania stanu).

Operatory nierówności dzielą się tak samo

!== jest ścisły, != luźny i obowiązuje ta sama rada:

Domyślnie używaj !==. Jeśli już dopuszczasz == null, możesz dopuścić też jego odpowiednik != null do sprawdzenia „ani null, ani undefined”.

Ściągawka do porównywania

Gdy musisz porównać dwie wartości, przejdź przez tę listę:

  • Typy proste, spodziewasz się tego samego typu? Użyj ===.
  • Sprawdzasz null lub undefined? x == null jest w porządku, jeśli pozwala na to twój przewodnik stylu, w przeciwnym razie x === null || x === undefined.
  • Sprawdzasz NaN? Number.isNaN(x).
  • Porównujesz obiekty po tożsamości? === robi dokładnie to, czego chcesz.
  • Porównujesz obiekty po zawartości? Napisz funkcję pomocniczą, użyj biblioteki albo serializuj. Wbudowane operatory tu nie pomogą.

Trzymaj się ===, traktuj == jako specjalne narzędzie do przypadku == null, a ominiesz dziwactwa porównań, które wypełniają listy FAQ o JavaScript.

Dalej: operatory

Równość to tylko wycinek zestawu operatorów JavaScript. Następna strona omawia resztę: operatory arytmetyczne, logiczne, przypisania i krótsze formy, z których korzystasz w codziennym kodzie.

Najczęściej zadawane pytania

Czym różni się == od === w JavaScript?

=== to równość ścisła: zwraca true tylko wtedy, gdy oba operandy mają ten sam typ i tę samą wartość. == to równość luźna: przed porównaniem konwertuje operandy do wspólnego typu. 1 === '1' daje false, ale 1 == '1' daje true, bo == najpierw zamienia string na liczbę.

Czy w JavaScript zawsze używać ===?

Domyślnie tak. === jest przewidywalny, a jego zasady łatwo zapamiętać. Jedynym częstym wyjątkiem jest x == null, które wygodnie dopasowuje zarówno null, jak i undefined. Większość linterów (reguła eqeqeq w ESLint) wymusza === i pozwala opcjonalnie włączyć ten jeden wzorzec.

Dlaczego NaN === NaN zwraca false?

Specyfikacja IEEE 754 mówi, że NaN nie jest równe niczemu, nawet samemu sobie. Dlatego każdy operator równości zwraca false, gdy w porównaniu bierze udział NaN. Żeby sprawdzić, czy wartość to NaN, użyj Number.isNaN(x) albo Object.is(NaN, NaN), które zwraca true.

Jak porównać dwa obiekty w JavaScript?

Zarówno ==, jak i === porównują obiekty po referencji, a nie po zawartości. {a: 1} === {a: 1} daje false, bo to dwa różne obiekty. Żeby porównać wartości, napisz własne sprawdzenie, użyj biblioteki, np. isEqual z Lodash, albo w przypadku prostych obiektów zserializuj je przez JSON.stringify.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ