Który operator równości (== vs ===) powinien być używany w porównaniach JavaScript?

5665

Używam JSLint, aby przejść przez JavaScript, i zwraca wiele sugestii, aby zastąpić ==(dwa znaki równości) znakiem ===(trzy znaki równości) podczas robienia rzeczy takich jak porównywanie idSele_UNVEHtype.value.length == 0wewnątrz ifinstrukcji.

Czy istnieje korzyści wydajność do zastąpienia ==z ===?

Wszelkie ulepszenia wydajności byłyby mile widziane, ponieważ istnieje wielu operatorów porównania.

Jeśli konwersja typu nie ma miejsca, czy nastąpiłby wzrost wydajności ==?

bcasp
źródło
134
Do kogo może być zainteresowany tym samym tematem === vs ==, ale w PHP, można przeczytać tutaj: stackoverflow.com/questions/2401478/hy-is-faster-than-in-php/...
Marco Demaio
257
Na wypadek, gdyby ktoś zastanawiał się w 2012 roku: ===jest znacznie szybszy niż ==. jsperf.com/comparison-of-comparisons
Ry-
25
@minitech powinno być, ponieważ nie wykonuje konwersji typów
Umur Kontacı
19
@minitech, wątpię, aby ktokolwiek uczynił swoją aplikację zauważalnie szybszą przy użyciu ===over ==. W rzeczywistości test porównawczy nie pokazuje dużej różnicy między obydwoma w nowoczesnych przeglądarkach. Osobiście zwykle używam ==wszędzie, chyba że naprawdę potrzebuję ścisłej równości.
laurent,
5
Oto część wykładu JS The Good Parts Crockforda, w którym omawia operatorów ===i ==: youtube.com/... Jeśli nie gra, to o 15:20
davidhiggins

Odpowiedzi:

6483

Operator ścisłej równości ( ===) zachowuje się identycznie jak abstrakcyjny operator równości ( ==), z tym wyjątkiem, że nie jest wykonywana konwersja typów, a typy muszą być takie same, aby można je było uznać za równe.

Odniesienia: Samouczek Javascript: Operatory porównania

==Operator będzie porównać do równości po wykonaniu niezbędnych konwersje typów . ===Operator nie zrobić konwersję, więc jeśli dwie wartości nie są tego samego typu ===po prostu wrócić false. Oba są równie szybkie.

Cytując doskonały JavaScript Douglasa Crockforda : The Good Parts ,

JavaScript ma dwa zestawy operatorów równości: ===i !==, i ich złych bliźniaków ==i !=. Te dobre działają w oczekiwany sposób. Jeśli dwa operandy są tego samego typu i mają tę samą wartość, wówczas ===produkuje truei !==produkuje false. Źli bliźniacy postępują właściwie, gdy operandy są tego samego typu, ale jeśli są innego rodzaju, próbują wymuszać wartości. zasady, według których to robią, są skomplikowane i niezapomniane. Oto niektóre z interesujących przypadków:

'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

Tabela porównawcza równości

Brak przechodniości jest niepokojący. Moja rada to nigdy nie używać złych bliźniaków. Zamiast tego zawsze używaj ===i !==. Wszystkie przedstawione porównania porównują wyniki falsez ===operatorem.


Aktualizacja:

Punkt dobry był wychowywany przez @Casebash w komentarzach iw @Phillipe Laybaert za odpowiedziami dotyczące obiektów. Dla obiektów ==i ===działaj zgodnie ze sobą (z wyjątkiem szczególnych przypadków).

var a = [1,2,3];
var b = [1,2,3];

var c = { x: 1, y: 2 };
var d = { x: 1, y: 2 };

var e = "text";
var f = "te" + "xt";

a == b            // false
a === b           // false

c == d            // false
c === d           // false

e == f            // true
e === f           // true

Szczególny przypadek ma miejsce, gdy porównujesz operację podstawową z obiektem, który ocenia tę samą operację podstawową, ze względu na jej metodę toStringlub valueOfmetodę. Rozważmy na przykład porównanie prymitywu łańcucha z obiektem łańcucha utworzonym za pomocą Stringkonstruktora.

"abc" == new String("abc")    // true
"abc" === new String("abc")   // false

Tutaj ==operator sprawdza wartości dwóch obiektów i zwraca true, ale ===widzi, że nie są tego samego typu i zwracają false. Który jest prawidłowy? To naprawdę zależy od tego, co próbujesz porównać. Radzę całkowicie ominąć pytanie i po prostu nie używaj Stringkonstruktora do tworzenia obiektów łańcuchowych z literałów łańcuchowych.

Odwołanie
http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3

Bill jaszczurka
źródło
236
=== nie jest szybszy, jeśli typy są takie same. Jeśli typy nie są takie same, === będzie szybsze, ponieważ nie będzie próbował wykonać konwersji.
Bill the Lizard
520
=== nigdy nie będzie wolniejszy niż ==. Oba sprawdzają typ, więc === nie robi nic więcej w porównaniu z ==, ale sprawdzanie typu może pozwolić === wyjść wcześniej, gdy typy nie są takie same.
Bill the Lizard
246
Zastąpienie wszystkich == /! = Przez === /! == zwiększa rozmiar pliku js, załadowanie zajmie więcej czasu. :)
Marco Demaio
92
„... zasady, według których to robią, są skomplikowane i niepamiętne ...” Teraz takie stwierdzenia sprawiają, że czujesz się bezpiecznie podczas programowania ...
Johan
47
Z Crockford: „Brak przechodniości jest niepokojący”. Jeśli opracujesz oprogramowanie i nie zauważysz braku przechodniości w niepokojącym operatorze porównania lub jeśli porównanie prędkości między == a === lub rozmiarem pliku / czasem ładowania ma pierwszeństwo przed przechodnim determinizmem zachowania operatora porównania, być może trzeba będzie wrócić i zacząć od nowa.
jinglesthula
1144

Korzystanie z ==operatora ( równość )

true == 1; //true, because 'true' is converted to 1 and then compared
"2" == 2;  //true, because "2" is converted to 2 and then compared

Korzystanie z ===operatora ( tożsamość )

true === 1; //false
"2" === 2;  //false

Wynika to z faktu, że operator równości ==dokonuje przymusu typu , co oznacza, że ​​interpreter niejawnie próbuje przekonwertować wartości przed porównaniem.

Z drugiej strony operator tożsamości ===nie stosuje przymusu typu , a zatem nie konwertuje wartości podczas porównywania, a zatem jest szybszy (zgodnie z tym testem porównawczym JS ), ponieważ pomija jeden krok.

Kalpesh Rajai
źródło
9
@ Software Monkey: nie dla typów wartości (liczba, wartość logiczna, ...)
Philippe Leybaert
33
Ponieważ nikt nie wspominał o tabeli równości Javascript, oto ona: dorey.github.io/JavaScript-Equality-Table
blasku
6
Czy w pierwszym stwierdzeniu jesteś pewien, że „prawda” jest konwertowana na 1, a nie 1 na prawdę?
Shadi Namrouti
2
Skąd się biorą terminy „równość” i „tożsamość”? Standard nie używa tych terminów. Nazywa ==„abstrakcyjną równością” i ===„ścisłą równością”. Przyznanie ==jakiegokolwiek rodzaju „równości” jest okropne, ponieważ nie jest przechodnie, ale po co się spierać? Mam jednak więcej problemów z „tożsamością”; Myślę, że ten termin jest dość mylący, choć „działa”. A tak na poważnie, kto ukuł termin „tożsamość”? Przeszukuję standard i nie mogłem go znaleźć.
Ray Toal,
1
„Tożsamość” to bardzo złe słowo. Porównania tożsamości we wszystkich używanych przeze mnie językach oznaczają jeden w tym samym obiekcie , tj. Dwie zmienne odniesienia wskazują nie tylko na równoważne byty, ale na ten sam byt.
Inigo
723

Interesujące obrazowe przedstawienie porównania równości między ==i ===.

Źródło: http://dorey.github.io/JavaScript-Equality-Table/


var1 === var2

Podczas korzystania ===z testów równości JavaScript wszystko jest takie, jak jest. Przed dokonaniem oceny nic nie jest konwertowane.

Ocena równości === w JS


var1 == var2

Podczas używania ==do testowania równości JavaScript mają miejsce niektóre funky konwersje.

Ocena równości == w JS

Morał historii:

Używaj, ===chyba że w pełni rozumiesz konwersje, które mają miejsce ==.

Szkopuł
źródło
3
@mfeineis masz na myśli === lub! == zamiast == lub! =. Nie chcę mylić nowych programistów;)
katalin_2003
2
z mojego doświadczenia, używanie trzech równych może powodować problemy i należy tego unikać, chyba że w pełni zrozumiałe. dwa równe daje znacznie lepsze wyniki, ponieważ 99% czasu naprawdę nie chcę, aby typy były równe.
vsync
12
@vsync: Jeśli naprawdę nie chcesz, aby typy były równe , powinieneś użyć trzech równości !
Niedziela
6
Jedyny wyjątek: możesz bezpiecznie użyć, x == nullaby sprawdzić, czy xjest nulllub undefined.
Andy,
1
@ user648026: Pytanie jest o równości porównaniu ==vs ===. Duże i małe litery i tak są nierówne i powrócą falsezarówno z operatorem, jak ==i z ===operatorem. Ponadto, słowa kluczowe true, false, undefined, null, Infinityistnieją w JS tylko w jednym przypadku i nie może być stosowany w górnych lub mieszanych przypadkach.
Snag
609

W odpowiedziach tutaj nie czytałem nic o tym, co oznacza równość . Niektórzy powiedzą, że ===to znaczy równe i tego samego typu , ale to nie jest tak naprawdę prawda. W rzeczywistości oznacza to, że oba operandy odnoszą się do tego samego obiektu lub, w przypadku typów wartości, mają tę samą wartość .

Weźmy następujący kod:

var a = [1,2,3];
var b = [1,2,3];
var c = a;

var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true

Tak samo tutaj:

var a = { x: 1, y: 2 };
var b = { x: 1, y: 2 };
var c = a;

var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true

Lub nawet:

var a = { };
var b = { };
var c = a;

var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true

To zachowanie nie zawsze jest oczywiste. W tej historii jest coś więcej niż równość i bycie tego samego rodzaju.

Reguła jest następująca:

Dla typów wartości (numery):
a === b Zwraca TRUE jeśliaibmają taką samą wartość i są tego samego typu

Dla typów referencyjnych:
a === b zwraca true, jeśliaibodwołuje się do dokładnie tego samego obiektu

Ciągów:
a === b Zwraca true jeśliaibto zarówno ciągi i zawierają dokładnych samych znaków


Ciągi: przypadek specjalny ...

Łańcuchy nie są typami wartości, ale w Javascripcie zachowują się jak typy wartości, więc będą „równe”, gdy znaki w łańcuchu będą takie same i gdy będą tej samej długości (jak wyjaśniono w trzeciej regule)

Teraz staje się interesujący:

var a = "12" + "3";
var b = "123";

alert(a === b); // returns true, because strings behave like value types

A co powiesz na to ?:

var a = new String("123");
var b = "123";

alert(a === b); // returns false !! (but they are equal and of the same type)

Myślałem, że łańcuchy zachowują się jak typy wartości? Cóż, zależy od kogo zapytasz ... W tym przypadku aib nie są tego samego typu. ajest typu Object, natomiast bjest typu string. Pamiętaj tylko, że utworzenie obiektu łańcucha za pomocą Stringkonstruktora powoduje utworzenie czegoś typu, Objectktóry przez większość czasu zachowuje się jak łańcuch .

Philippe Leybaert
źródło
6
activa: Wyjaśniłbym, że ciągi są tak równe tylko wtedy, gdy są dosłowne. new String („abc”) === „abc” jest fałszem (według moich badań).
Lawrence Dol
3
new Number() == "0". Również w przeglądarce Firefox:(function(){}) == "function () {\n}"
Thomas Eding
3
Dziękujemy za wyjaśnienie dlaczego new String("123") !== "123". Są to różne typy. Proste, ale mylące.
styfle
21
Stringobiekty zachowują się tak samo, jak każdy inny obiekt . new Stringnigdy nie powinien być używany, ponieważ nie tworzy to prawdziwych ciągów. Prawdziwy ciąg znaków i można go tworzyć za pomocą literałów lub wywoływania Stringjako funkcji bez new , na przykład:String(0); //"0", Real string, not an object
Esailija
6
Ale w szczegółowych przypadkach operator „==” zachowuje się dokładnie tak samo.
Yaron Levi
270

Pozwól mi dodać tę radę:

W razie wątpliwości przeczytaj specyfikację !

ECMA-262 to specyfikacja języka skryptowego, którego JavaScript jest dialektem. Oczywiście w praktyce ważniejsze jest zachowanie najważniejszych przeglądarek niż ezoteryczna definicja tego, jak należy postępować. Ale pomocne jest zrozumienie, dlaczego nowy ciąg („a”)! == „a” .

Pozwól mi wyjaśnić, jak przeczytać specyfikację, aby wyjaśnić to pytanie. Widzę, że w tym bardzo starym temacie nikt nie miał odpowiedzi na bardzo dziwny efekt. Jeśli więc potrafisz przeczytać specyfikację, pomoże ci to w swoim zawodzie. Jest to umiejętność nabyta. Kontynuujmy.

Przeszukiwanie pliku PDF dla === prowadzi mnie do strony 56 specyfikacji: 11.9.4. The Strict Equals Operator (===) , a po przejściu przez specyfikację znajduję:

11.9.6 Algorytm
porównania ścisłej równości Porównanie x === y, gdzie xiy są wartościami, daje wartość prawda lub fałsz . Takie porównanie wykonuje się w następujący sposób:
  1. Jeśli typ (x) różni się od typu (y), zwróć false .
  2. Jeśli Typ (x) jest Nieokreślony, zwróć true .
  3. Jeśli Type (x) ma wartość Null, zwróć wartość true .
  4. Jeśli typ (x) nie jest liczbą, przejdź do kroku 11.
  5. Jeśli x to NaN , zwróć false .
  6. Jeśli y jest NaN , zwróć false .
  7. Jeśli x jest tą samą liczbą, co y, zwróć true .
  8. Jeśli x to +0, a y to −0, zwróć true .
  9. Jeśli x to −0, a y to +0, zwróć true .
  10. Zwróć false .
  11. Jeśli Type (x) jest String, zwróć true, jeśli xiy są dokładnie tą samą sekwencją znaków (ta sama długość i te same znaki w odpowiednich pozycjach); w przeciwnym razie zwróć false .
  12. Jeśli Type (x) ma wartość logiczną, zwróć true, jeśli xiy są prawdziwe lub oba false ; w przeciwnym razie zwróć false .
  13. Zwróć wartość truejeśli xiy odnoszą się do tego samego obiektu lub jeśli odnoszą się do obiektów połączonych ze sobą (patrz 13.1.2). W przeciwnym razie zwróć false .

Interesujący jest krok 11. Tak, łańcuchy są traktowane jako typy wartości. Ale to nie wyjaśnia, dlaczego nowy ciąg („a”)! == „a” . Czy mamy przeglądarkę niezgodną z ECMA-262?

Nie tak szybko!

Sprawdźmy typy operandów. Wypróbuj sam, zawijając je w typeof () . Uważam, że nowy ciąg znaków („a”) jest obiektem i używany jest krok 1: zwróć false, jeśli typy są różne.

Jeśli zastanawiasz się, dlaczego nowy ciąg („a”) nie zwraca ciągu, co powiesz na jakieś ćwiczenie polegające na czytaniu specyfikacji? Baw się dobrze!


Aidiakapi napisał to w komentarzu poniżej:

Ze specyfikacji

11.2.2 Nowy operator :

Jeśli Type (konstruktor) nie jest Object, wyrzuć wyjątek TypeError.

Innymi słowy, jeśli String nie byłby typu Object, nie można go użyć z nowym operatorem.

new zawsze zwraca Object, nawet dla konstruktorów String . I niestety! Semantyka wartości dla łańcuchów (patrz krok 11) zostaje utracona.

A to w końcu oznacza: nowy ciąg („a”)! == „a” .

dokładnie
źródło
Wynik typu (x) ma być taki sam jak typof?
Dfr
@nalply Nie do końca rozumiem obawy związane z zachowaniem new String('x'), ponieważ nigdy nie widziałem żadnego kodu w środowisku naturalnym, który używa prymitywnych obiektów otoki i nie sądzę, aby istniał dobry powód, szczególnie w dzisiejszych czasach. Czy kiedykolwiek napotkałeś kod, który to robi?
Andy,
@Andy problemem jest złośliwy lub po prostu niechlujny kod innej firmy, więc nie możesz założyć, że nikt nie używa new String().
dokładnie
Jeśli jest niechlujny, === to jak się dowiesz. Jeśli jest złośliwy, myślę, że new String()to prawdopodobnie najmniejsze z twoich zmartwień. Rozumiem obawy w teorii, ale czy masz jakieś przykłady z prawdziwego świata? Dla mnie to jak stary niepokój, że ktoś mógłby ustawić undefinedinną wartość.
Andy,
Nie wiem, skąd to masz, ale twój algorytm porównania popełnił błąd w kroku 2. Sekcja „7.2.15 Porównanie ścisłej równości” najpierw sprawdza, czy typy są takie same, a jeśli tak, to czy są liczbą. Jeśli nie, to używana jest sekcja „7.2.12 SameValueNonNumber (x, y)”.
Rusty Core
101

W PHP i JavaScript jest to operator ścisłej równości. Co oznacza, że ​​porówna zarówno typ, jak i wartości.

Shiki
źródło
10
@David: poprawne. Dlatego ta odpowiedź jest niedokładna (lub nawet błędna)
Philippe Leybaert
7
@David var a = {}, b = {}; a == bzwraca wartość false.
nyuszika7h
6
Tak: Dwa różne obiekty tego samego typu i wartości porównują fałsz, tzn. Ta odpowiedź jest po prostu błędna. Dlaczego ma 50 głosów pozytywnych?
Alexis
4
Zdaję sobie sprawę, że jest to stare, ale wyjaśnienie, dlaczego ta odpowiedź jest nadal „poprawna”, wynika z tego, że w przykładzie var a = {}, b = {};Chociaż oba są ai brzeczywiście oba są przedmiotem, ale technicznie rzecz biorąc nie są one tej samej wartości. Są to różne przypadki. Pamiętaj, że porównywanie instancji zachowuje się inaczej niż porównywanie operacji podstawowych. Co prawdopodobnie przyczynia się do tego zamieszania. Podobne zachowanie porównawcze zobaczysz, jeśli użyjesz wersji instancji pierwotnych typów danych. Np new String('asdf')lub new Number(5). Np .: new Number(5) == new Number(5)jest fałszywe, mimo że mają tę samą wartość.
Norman Breau
1
Wszyscy zapominamy, że odwołanie do obiektu jest w rzeczywistości typem wartości, ponieważ jest wskaźnikiem do gniazda pamięci. Porównanie obiektów nie porównuje „wartości obiektu”, ale czy oba wskaźniki są takie same, co oznaczałoby, że odnoszą się do tego samego gniazda pamięci. Jest to bardzo subtelna różnica w porównywaniu typów, ponieważ operator „===” naprawdę musi powiedzieć „jeśli typ, wartość i odwołanie do obiektu w pamięci są takie same”.
Stokely
101

Przetestowałem to w Firefoksie z Firebug, używając następującego kodu:

console.time("testEquality");
var n = 0;
while(true) {
    n++;
    if(n==100000) 
        break;
}
console.timeEnd("testEquality");

i

console.time("testTypeEquality");
var n = 0;
while(true) {
    n++;
    if(n===100000) 
        break;
}
console.timeEnd("testTypeEquality");

Moje wyniki (przetestowane pięć razy i uśrednione):

==: 115.2
===: 114.4

Powiedziałbym więc, że drobna różnica (pamiętaj, że to ponad 100 000 iteracji) jest znikoma. Wydajność nie jest powodem do zrobienia ===. Wpisz bezpieczeństwo (cóż, tak bezpieczne, jak to możliwe w JavaScript), a jakość kodu to.

Simon Scarfe
źródło
3
Bardziej niż bezpieczeństwo typu, potrzebujesz logicznej poprawności - czasem chcesz, aby rzeczy były prawdziwe, gdy się ==nie zgadzasz.
rpjohnst
4
Jak się mają teraz do porównania, gdy ==operator ma rzeczywistą kooperację typów ? Pamiętaj, że wtedy następuje wzrost wydajności.
Hubert OG
2
ZNACZNA różnica przy prawidłowym testowaniu z wyżej wymienionych powodów szybszego sprawdzania tylko nierówności typu. jsfiddle.net/4jhuxkb2
Doug Morrow
Wydajność czegoś takiego mierzysz w operacjach / sekundę, a nie w pojedynczym teście w jednej przeglądarce (jednej z około 5% udziałem w rynku) za pomocą console.time (), używając testu, który nie wymaga przymusu typu (cały powód jest wolniejszy). Jest to całkowicie bezsensowny test. Masz rację, że wydajność nie jest powodem do ===nadużywania, ==ale mylisz się, że ich wydajność jest zasadniczo równa i że uważasz, że ten test dowodzi, że i że wiele innych osób zgodziło się, jest dla mnie całkowicie absurdalne.
Stephen M Irving,
96

W JavaScript oznacza tę samą wartość i typ.

Na przykład,

4 == "4" // will return true

ale

4 === "4" // will return false 
Dimitar
źródło
87

=== operatora nazywana jest ścisłe operatora porównania, nie różnią się od == operatora.

Weźmy 2 zmienne a i b.

Aby „a == b” mogło zostać ocenione jako prawda, aib musi mieć tę samą wartość .

W przypadku „a === b” aib muszą mieć tę samą wartość, a także ten sam typ, aby mógł zostać oceniony jako prawdziwy.

Weź następujący przykład

var a = 1;
var b = "1";

if (a == b) //evaluates to true as a and b are both 1
{
    alert("a == b");
}

if (a === b) //evaluates to false as a is not the same type as b
{
    alert("a === b");
}

Podsumowując ; użycie operatora == może dać wartość true w sytuacjach, w których nie chcesz, więc użycie operatora === byłoby bezpieczniejsze.

W scenariuszu użycia 90% nie będzie miało znaczenia, którego używasz, ale dobrze jest znać różnicę, gdy pewnego dnia otrzymasz nieoczekiwane zachowanie.

Doktorze Jones
źródło
82

Dlaczego ==jest tak nieprzewidywalny?

Co otrzymujesz, porównując pusty ciąg ""z liczbą zero 0?

true

Tak, zgadza się ==to z pustym ciągiem, a liczba zero to ten sam czas.

I to się nie kończy, oto kolejny:

'0' == false // true

Z tablicami robi się naprawdę dziwnie.

[1] == true // true
[] == false // true
[[]] == false // true
[0] == false // true

Potem dziwniejsze ze sznurkami

[1,2,3] == '1,2,3' // true - REALLY?!
'\r\n\t' == 0 // true - Come on!

Pogarsza się:

Kiedy równość nie jest równa?

let A = ''  // empty string
let B = 0   // zero
let C = '0' // zero string

A == B // true - ok... 
B == C // true - so far so good...
A == C // **FALSE** - Plot twist!

Powiem to jeszcze raz:

(A == B) && (B == C) // true
(A == C) // **FALSE**

A to tylko szalone rzeczy, które dostajesz z prymitywami.

To zupełnie nowy poziom szaleństwa, gdy używasz ==przedmiotów.

W tym momencie prawdopodobnie zastanawiasz się ...

Dlaczego to się dzieje?

Jest tak, ponieważ w przeciwieństwie do „triple equals” ( ===), który sprawdza tylko, czy dwie wartości są takie same.

==robi całą masę innych rzeczy .

Ma specjalną obsługę dla funkcji, specjalną obsługę dla wartości zerowych, niezdefiniowanych, ciągów, jak to nazwiesz.

Robi się dziwnie.

W rzeczywistości, jeśli spróbujesz napisać funkcję, która robi to ==, co by wyglądała, wyglądałby mniej więcej tak:

function isEqual(x, y) { // if `==` were a function
    if(typeof y === typeof x) return y === x;
    // treat null and undefined the same
    var xIsNothing = (y === undefined) || (y === null);
    var yIsNothing = (x === undefined) || (x === null);

    if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);

    if(typeof y === "function" || typeof x === "function") {
        // if either value is a string 
        // convert the function into a string and compare
        if(typeof x === "string") {
            return x === y.toString();
        } else if(typeof y === "string") {
            return x.toString() === y;
        } 
        return false;
    }

    if(typeof x === "object") x = toPrimitive(x);
    if(typeof y === "object") y = toPrimitive(y);
    if(typeof y === typeof x) return y === x;

    // convert x and y into numbers if they are not already use the "+" trick
    if(typeof x !== "number") x = +x;
    if(typeof y !== "number") y = +y;
    // actually the real `==` is even more complicated than this, especially in ES6
    return x === y;
}

function toPrimitive(obj) {
    var value = obj.valueOf();
    if(obj !== value) return value;
    return obj.toString();
}

Co to znaczy?

Oznacza ==to, że jest skomplikowane.

Ponieważ jest to skomplikowane, trudno jest wiedzieć, co się stanie, gdy go użyjesz.

Co oznacza, że ​​możesz skończyć z błędami.

Morał tej historii to ...

Spraw, aby twoje życie było mniej skomplikowane.

Użyj ===zamiast ==.

Koniec.

Luis Perez
źródło
Twój looseEqualjest zły. Function == Function.toString()to prawda, alelooseEqual(Function, Function.toString()) fałszem. Nie wiesz, dlaczego odfiltrowujesz funkcje na początku.
Oriol
@Oriol miałeś rację, zaktualizowałem kod, aby to uwzględnić, FYI na podstawie moich testów nie wystarczyło usunąć filtr dla „funkcji”, zamiast tego „funkcje” musiały być traktowane zupełnie inaczej.
Luis Perez,
Pamiętaj, że specyfikacja nie traktuje funkcji inaczej, są tylko obiektami. Problem wydaje się polegać na typeof x === "object"sprawdzeniu, czy jest to obiekt, ale `typeof działa tylko dla prymitywów niepustych. Być może zainteresuje Cię moja lista właściwych sposobów sprawdzania, czy wartość jest obiektem
Oriol
Próbowałem traktować funkcje i obiekty tak samo, ale stwierdziłem, że wyniki były niepoprawne. Na przykład, jeśli funkcje byłyby traktowane jak obiekty, to porównanie funkcji z obiektem, który implementuje funkcję valueOf () lub toString () pasującą do funkcji, przejdzie, ale w rzeczywistości tak nie jest. Przykład: (function blah() { console.log("test"); }) != {valueOf:function(){return "function blah() { console.log(\"test\"); }";}}- sprawdź ten JS Fiddle, który uruchamia wszystkie testy: jsfiddle.net/luisperezphd/7k6gcn6g (tam 1225 permutacji testowych)
Luis Perez
1
Masz rację, świetne spostrzeżenia, to podkreśla główny punkt, który ==robi wiele rzeczy, co bardzo utrudnia przewidywanie wyników, a jednocześnie ===jest o wiele prostszy i przewidywalny, co jest jednym z głównych powodów, dla ===których zalecany jest wybór. (Dodam notatkę do odpowiedzi, w której wspominasz o swoim punkcie)
Luis Perez,
81

===sprawdza, czy te same strony są równe pod względem rodzaju i wartości .


Przykład:

'1' === 1 // will return "false" because `string` is not a `number`

Typowy przykład:

0 == ''  // will be "true", but it's very common to want this check to be "false"

Kolejny częsty przykład:

null == undefined // returns "true", but in most cases a distinction is necessary

Wiele razy na bez typu check byłby przydatny, bo nie obchodzi mnie, jeśli wartość jest albo undefined, null, 0 lub""

vsync
źródło
7
także'string' !== 'number'
Homer
71

Schemat blokowy wykonania JavaScript dla ścisłej równości / porównania '==='

Javascript ścisła równość

Schemat blokowy wykonania JavaScript dla nie ścisłej równości / porównania „==”

JavaScript nierówność

Samar Panda
źródło
Nie rozumiem, dlaczego stringstrzałka wskazuje duże szare pole, czy to znaczy, że przerywacz rzuca ciąg na liczbę?
vsync
@vsync Wskazuje na opcję ciągu w szarym polu, tzn. ciąg -> # || NaN. JavaScript nie jest językiem skryptowym, tzn. Zasadniczo może mieć dowolny typ zmiennej. Wskazuje więc na to szare pole.
Samar Panda,
Po prostu zapytałem, czy jest to do celów rzutowych, ponieważ stringma być porównywany z typem number, więc przerywacz patrzy na to, co łańcuch powinien być porównywany i odpowiednio rzutuje?
vsync
1
Duże szare pole jest tym ToNumber, co powróci, gdy otrzyma różne typy, więc jeśli otrzyma ciąg, wybierze tylko ostatnią opcję (i zamieni ją na liczbę). ==używa ToNumbertylko w przypadkach string == numberlub boolean == anythingpowyżej (i tylko na string/ boolean). Środek ten ==nie będzie konwertować undefinedlub nullchociaż są one w szarym polu. (Dla dowolnej kombinacji jednego undefinedlub nullobu ==będzie zawsze zwracać true. Również to, czy wartość jest po lewej czy po prawej stronie, nie ma znaczenia, ==(i ===) zwróci ten sam wynik.)
user2033427
55

JavaScript === vs == .

0==false   // true
0===false  // false, because they are of a different type
1=="1"     // true, auto type coercion
1==="1"    // false, because they are of a different type
Anik Islam Abhi
źródło
54

Oznacza to równość bez przymusu typu przymus typu oznacza, że ​​JavaScript nie konwertuje automatycznie żadnych innych typów danych na typy danych łańcuchowych

0==false   // true,although they are different types

0===false  // false,as they are different types

2=='2'    //true,different types,one is string and another is integer but 
            javaScript convert 2 to string by using == operator 

2==='2'  //false because by using === operator ,javaScript do not convert 
           integer to string 

2===2   //true because both have same value and same types 
Pop Catalin
źródło
48

W typowym skrypcie nie będzie różnicy w wydajności. Ważniejszy może być fakt, że tysiąc „===” jest o 1 KB większy niż tysiąc „==” :) Profile JavaScript mogą ci powiedzieć, czy w twoim przypadku występuje różnica w wydajności.

Ale osobiście zrobiłbym to, co sugeruje JSLint. To zalecenie nie występuje z powodu problemów z wydajnością, ale dlatego, że wymuszenie typu ('\t\r\n' == 0)jest prawdziwe.

Constantin
źródło
4
Nie zawsze prawda. W przypadku kompresji gzip różnica byłaby prawie znikoma.
Daniel X Moore
1
Zgadzam się, ale tysiąc „===” oznacza także 10 tysięcy innych wierszy kodu, więc 1kb mniej więcej ...;)
Jonny
jeśli
46

Operator równego porównania == jest mylący i należy go unikać.

Jeśli MUSZĄ żyć z nim, a następnie zapamiętać następujące 3 rzeczy:

  1. Nie jest przechodni: (a == b) i (b == c) nie prowadzi do (a == c)
  2. To wyklucza się wzajemnie z negacją: (a == b) i (a! = B) zawsze mają przeciwne wartości boolowskie, wszystkie a i b.
  3. W razie wątpliwości naucz się na pamięć poniższej tabeli prawdy:

RÓWNY TABELA PRAWDY OPERATORA W JAVASCRIPT

  • Każdy wiersz w tabeli to zestaw 3 wzajemnie „równych” wartości, co oznacza, że ​​dowolne 2 wartości są równe przy użyciu znaku równości == *

** DZIWNY: zwróć uwagę, że dowolne dwie wartości w pierwszej kolumnie nie są równe w tym sensie. **

''       == 0 == false   // Any two values among these 3 ones are equal with the == operator
'0'      == 0 == false   // Also a set of 3 equal values, note that only 0 and false are repeated
'\t'     == 0 == false   // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\r'     == 0 == false   // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\n'     == 0 == false   // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\t\r\n' == 0 == false   // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

null == undefined  // These two "default" values are not-equal to any of the listed values above
NaN                // NaN is not equal to any thing, even to itself.
CuongHuyTo
źródło
39

Prawdopodobnie nie będzie żadnej różnicy w wydajności między tymi dwiema operacjami w twoim użyciu. Nie ma potrzeby konwersji typu, ponieważ oba parametry są już tego samego typu. Obie operacje będą miały porównanie typów, a następnie porównanie wartości.

Sean
źródło
38

Tak! To ma znaczenie.

===operator w javascript sprawdza wartość, a także typ, w którym jako ==operator sprawdza tylko wartość (w razie potrzeby dokonuje konwersji typu) .

wprowadź opis zdjęcia tutaj

Możesz to łatwo przetestować. Wklej następujący kod do pliku HTML i otwórz go w przeglądarce

<script>

function onPageLoad()
{
    var x = "5";
    var y = 5;
    alert(x === 5);
};

</script>

</head>

<body onload='onPageLoad();'>

Otrzymasz „ fałsz ” w pogotowiu. Teraz zmodyfikuj onPageLoad()metodę, aby alert(x == 5);się spełniła .

Aniket Thakur
źródło
33

=== operator sprawdza wartości, a także typy zmiennych pod kątem równości.

== operator sprawdza tylko wartość zmiennych pod kątem równości.

Niraj CHoubey
źródło
32

To ścisły test kontrolny.

To dobrze, zwłaszcza jeśli sprawdzasz między 0 a fałszem i null.

Na przykład, jeśli masz:

$a = 0;

Następnie:

$a==0; 
$a==NULL;
$a==false;

Wszystkie zwracane są prawdą i możesz tego nie chcieć. Załóżmy, że masz funkcję, która może zwrócić 0. indeks tablicy lub false w przypadku awarii. Jeśli sprawdzisz za pomocą „==” false, możesz uzyskać mylący wynik.

Więc z tym samym co powyżej, ale z surowym testem:

$a = 0;

$a===0; // returns true
$a===NULL; // returns false
$a===false; // returns false
Daniel
źródło
3
W JavaScript jest to całkowicie błędne i błędnie niekompletne. 0 != null. -1
Ry-
31

JSLint czasami daje nierealistyczne powody do modyfikacji rzeczy. ===ma dokładnie taką samą wydajność jak== jakby typy były już takie same.

Jest szybszy tylko wtedy, gdy typy nie są takie same, w którym to przypadku nie próbuje konwertować typów, ale bezpośrednio zwraca wartość false.

Więc IMHO, JSLint może być użyte do napisania nowego kodu, ale za wszelką cenę należy unikać niepotrzebnej nadmiernej optymalizacji.

Czyli, nie ma powodu, aby zmienić ==się ===w kontroli jak if (a == 'test')gdy wiesz to na fakt, że może być tylko String.

Modyfikacja dużej ilości kodu w ten sposób marnuje czas programistów i recenzentów i nic nie osiąga.

proch
źródło
30

Po prostu

==oznacza porównanie operandów z type conversion

I

===oznacza porównanie operandów bez type conversion

Konwersja typów w javaScript oznacza, że ​​javaScript automatycznie konwertuje wszystkie inne typy danych na typy danych łańcuchowych.

Na przykład:

123=='123'   //will return true, because JS convert integer 123 to string '123'
             //as we used '==' operator 

123==='123' //will return false, because JS do not convert integer 123 to string 
            //'123' as we used '===' operator 
Amit
źródło
26

Prostym przykładem jest

2 == '2'  -> true, values are SAME because of type conversion.

2 === '2'  -> false, values are NOT SAME because of no type conversion.
Vikas
źródło
25

Dwie najlepsze odpowiedzi, o których mowa, == oznacza równość, a === oznacza tożsamość. Niestety to stwierdzenie jest nieprawidłowe.

Jeśli oba operandy == są obiektami, są one porównywane w celu sprawdzenia, czy są tym samym obiektem. Jeśli oba operandy wskazują ten sam obiekt, operator równości zwraca wartość true. W przeciwnym razie dwa nie są równe.

var a = [1, 2, 3];  
var b = [1, 2, 3];  
console.log(a == b)  // false  
console.log(a === b) // false  

W powyższym kodzie zarówno ==, jak i === stają się fałszywe, ponieważ aib nie są tymi samymi obiektami.

To znaczy: jeśli oba operandy == są obiektami, == zachowuje się tak samo jak ===, co oznacza również tożsamość. Zasadnicza różnica między tymi dwoma operatorami polega na konwersji typu. == ma konwersję, zanim sprawdzi równość, ale === nie.

Harry He
źródło
24

Zasadniczo wolałbym używać ===zamiast ==(i !==zamiast !=).

Powody są wyjaśnione w odpowiedziach powyżej, a także Douglas Crockford jest całkiem jasny ( JavaScript: The Good Parts ).

Istnieje jednak jeden wyjątek : == nulljest skutecznym sposobem sprawdzenia, czy „jest zerowy lub niezdefiniowany”:

if( value == null ){
    // value is either null or undefined
}

Na przykład jQuery 1.9.1 używa tego wzorca 43 razy, a moduł sprawdzania składni JSHint zapewnia nawet eqnullopcję relaksacyjną z tego powodu.

Z przewodnika po stylu jQuery :

Należy stosować ścisłe kontrole równości (===) na korzyść ==. Jedynym wyjątkiem jest sprawdzanie niezdefiniowanego i zerowego za pomocą null.

// Check for both undefined and null values, for some important reason. 
undefOrNull == null;
mar10
źródło
22

Problem polega na tym, że możesz łatwo wpaść w kłopoty, ponieważ JavaScript ma wiele niejawnych konwersji, co oznacza ...

var x = 0;
var isTrue = x == null;
var isFalse = x === null;

Który wkrótce stanie się problemem. Najlepszą próbkę tego, dlaczego niejawna konwersja jest „zła”, można pobrać z tego kodu w MFC / C ++, który faktycznie skompiluje się z powodu niejawnej konwersji z CString na UCHWYT, który jest typem wskaźnika typu ...

CString x;
delete x;

Co oczywiście podczas działania robi bardzo nieokreślone rzeczy ...

Google za niejawne konwersje w C ++ i STL, aby uzyskać niektóre argumenty przeciwko niemu ...

Thomas Hansen
źródło
2
0 == nullto fałsz.
Garrett
21

Porównanie równości:

Operator ==

Zwraca true, gdy oba operandy są równe. Przed porównaniem operandy są konwertowane na ten sam typ.

>>> 1 == 1
true
>>> 1 == 2
false
>>> 1 == '1'
true

Porównanie równości i typów:

Operator ===

Zwraca wartość true, jeśli oba operandy są równe i tego samego typu. Ogólnie jest to lepsze i bezpieczniejsze, jeśli porównasz w ten sposób, ponieważ nie ma konwersji typu „za kulisami”.

>>> 1 === '1'
false
>>> 1 === 1
true
użytkownik2601995
źródło
20

Oto przydatna tabela porównawcza, która pokazuje konwersje, które mają miejsce, oraz różnice między ==i ===.

Jak stwierdza wniosek:

„Użyj trzech równych, chyba że w pełni rozumiesz konwersje zachodzące dla dwóch równych”.

http://dorey.github.io/JavaScript-Equality-Table/

Christian Hagelid
źródło
20

zerowe i nieokreślone są nicością, to znaczy

var a;
var b = null;

Tutaj ai bnie mają wartości. Natomiast 0, false i „” są wartościami. Jedną wspólną cechą między nimi jest to, że wszystkie są wartościami fałszowania, co oznacza, że ​​wszystkie spełniają warunki fałszowania.

Zatem 0, fałsz i „” razem tworzą podgrupę. Z drugiej strony, null i undefined tworzą drugą podgrupę. Sprawdź porównania na poniższym obrazku. zero i nieokreślone byłyby równe. Pozostałe trzy będą sobie równe. Ale w JavaScript wszystkie są traktowane jako warunki do fałszowania.

Wpisz opis zdjęcia tutaj

Jest to to samo, co każdy obiekt (jak {}, tablice itp.), Niepuste ciągi i logiczna prawda są warunkami prawdziwymi. Ale nie wszystkie są równe.

vivek_nk
źródło