Start with strict equality

The examples in this article can be entered directly into the developer console of a modern browser. Each expression returns a boolean: true or false. For most application code, === is a useful default because it does not convert one operand to another type before comparing them.

For example, 5 === 5 is true, while 5 === "5" is false. The first expression compares two numbers; the second compares a number with a string. Likewise, false === 0 is false, even though those values can behave similarly in some contexts. Using === makes a type mismatch visible rather than silently treating the values as equal.

Strict equality has two less intuitive cases. NaN === NaN is false, because NaN is not strictly equal to any value, including itself. Meanwhile, 0 === -0 is true. These results matter when you are deliberately checking for NaN or need to distinguish the sign of zero; they rarely change an ordinary comparison of user-facing values.

What loose equality converts

The == operator uses loose equality. When the operands have different types, JavaScript may convert a value before comparing it. For instance, 5 == "5" is true because the numeric string can be converted to the number 5. Similarly, false == 0 is true. By contrast, 5 === "5" and false === 0 are both false.

Conversions can be surprising when arrays are involved. Try [] == 0 in the console: it returns true. In this comparison, the empty array is converted to a primitive value, then the resulting empty string is converted to zero. That behavior follows JavaScript's comparison rules, but it is not a good reason to use == as a general shortcut.

One specific loose-equality pattern can be intentional: value == null is true when value is either null or undefined. It is false for values such as 0, false, and "". If you use this pattern, make its purpose clear to readers of the code. When only one of null or undefined should match, use === with that specific value instead.

Where Object.is differs

Object.is(a, b) compares two values without the type conversions performed by ==. For most primitive values, its result matches ===: Object.is(5, 5) is true, and Object.is(5, "5") is false. It is a function call rather than an operator, so both values go inside the parentheses.

There are two important differences from ===. Object.is(NaN, NaN) is true, while NaN === NaN is false. Object.is(0, -0) is false, while 0 === -0 is true. The same signed-zero distinction applies to negative and positive zero regardless of which one appears first.

Use Object.is when those distinctions are part of what you need to test, such as deciding whether a stored numeric value has changed. Do not assume it is a deeper or more flexible comparison: it does not inspect the contents of arrays or objects. For a straightforward test of whether a value is NaN, Number.isNaN(value) may communicate the intent more directly.

Objects are compared by identity, not contents

Create two separate arrays in the console: const first = [1, 2]; const second = [1, 2];. Then evaluate first === second, first == second, and Object.is(first, second). All three return false. Although the arrays contain the same elements, they are different objects. Loose equality does not convert two objects merely because their contents look alike.

Now assign const alias = first;. Each of first === alias, first == alias, and Object.is(first, alias) returns true: both names refer to the same array. Ordinary objects behave the same way. For example, { score: 1 } === { score: 1 } is false because each object literal creates a separate object.

When you need to compare contents, define what equality means for your data. For a small record, that might mean comparing selected properties with ===. For an array, you might check its length and compare corresponding elements. Neither approach automatically handles every kind of nested value, so choose a method that fits the structure you expect.

Choose the comparison that expresses your intent

Reach for === when values should have the same type and value, or when two variables should refer to the same object. Use == only when you want its conversion rules and can explain the expected inputs; the deliberate value == null check is one example. Choose Object.is when NaN should match itself or when positive and negative zero must count as different.

If a comparison produces an unexpected result, inspect the operands before changing operators. In the browser console, typeof value can help reveal whether an input is a string, number, or another type. Converting an input explicitly at the boundary of your program often makes later comparisons easier to understand than relying on == to do the conversion during each check.

Back to category ↗