What is the difference between == and === in JavaScript?
=== (strict equality) is true only if both values have the same type and the same value. == (loose equality) first converts the values to a common type and then compares, which gives surprising results like 0 == "" being true. Use === by default.
Explain it simply
Imagine checking a ₹100 note. A strict cashier (===) checks that it is a real ₹100 note. A relaxed cashier (==) will also accept a ₹100 coupon, a cheque for ₹100, or a slip of paper that says "100", because they first try to turn everything into "something worth 100" before comparing.
== is called loose equality. It converts (coerces) values to the same type before comparing. === is strict equality. It never converts; if the types differ, the answer is simply false.
Example
console.log(5 === 5); // Output: true
console.log(5 === "5"); // Output: false
console.log(5 == "5"); // Output: true
console.log(0 == ""); // Output: true
console.log(0 == "0"); // Output: true
console.log("" == "0"); // Output: false
console.log(null == undefined); // Output: true
console.log(null === undefined); // Output: false
console.log(null == 0); // Output: false
console.log([] == false); // Output: true
console.log({} === {}); // Output: false
console.log(NaN === NaN); // Output: false
console.log(Number.isNaN(NaN)); // Output: trueNotice that 0 == "" and 0 == "0" are both true, but "" == "0" is false. Loose equality is not even consistent with itself, which is why most teams avoid it.
How it works
=== checks:
- Are the types different? Return
false. - Otherwise compare the values. Objects and arrays are compared by reference: two separate objects are never equal, even if they look the same.
== follows extra steps when the types differ:
nullandundefinedare equal to each other and to nothing else.- A number and a string: the string is converted to a number (
"5"becomes5,""becomes0). - A boolean is converted to a number first (
truebecomes1,falsebecomes0). - An object compared with a primitive is converted to a primitive (
[]becomes"", then0).
So [] == false becomes "" == 0, then 0 == 0, which is true.
Real-world use
Form inputs always give strings. If a user types "18" into an age field, age === 18 is false. The right fix is to convert explicitly, Number(age) === 18, rather than relying on ==. This keeps the conversion visible to anyone reading the code.
The one place many developers do use == on purpose is value == null, which is a short way to check for both null and undefined.
Common mistakes
- Using
==to compare user input with numbers and getting matches for empty strings. - Expecting two arrays or objects with the same content to be
===. They are different references. - Checking for NaN with
=== NaN. It is never true; useNumber.isNaN. - Thinking
===is "faster" as the main reason to use it. The real reason is predictable behaviour.
What to say in the interview
"=== is strict equality: it returns true only if both type and value are the same, with no conversion. == is loose equality: it converts both sides to a common type first, which leads to cases like 0 == '' being true and [] == false being true. I use === everywhere and convert types explicitly, for example with Number(). The one exception people allow is x == null, which checks for both null and undefined. Also, objects are compared by reference, and NaN is not equal to itself, so I use Number.isNaN."
Follow-up questions
- Why is
[] == ![]true? - What is
Object.isand how is it different from===? - How would you compare two objects by their contents?
Go deeper
Read these once the basics above feel easy.
Object.is(a, b) is like === with two differences: Object.is(NaN, NaN) is true, and Object.is(0, -0) is false, while 0 === -0 is true. Map, Set and includes use a similar rule called SameValueZero, which treats NaN as equal to NaN, so [NaN].includes(NaN) is true even though [NaN].indexOf(NaN) is -1.