Triple Equals vs Double Equals in JavaScript
In JavaScript, there are technically 4 different ways of comparing whether 2 values are equal. The 2 most common ways are the == operator and the === operator, also known as abstract equality comparison and strict equality comparison.
Strict Equality With ===
Given 2 values x and y, here's how JavaScript checks whether x === y:
- Check the types of
xandy. If they are different types, returnfalse. - If
xandyare numbers, first check if eitherxoryisNaN, and returnfalseif one isNaN. If bothxandyare either+0or-0, returntrue. Otherwise, check to see if they are the same number. - If
xandyare bothnullor bothundefined, returntrue. - If
xandyare both booleans, both strings, or both symbols, compare them by value. - If
xandyare both objects, return true if and only if they reference the same object.
In short, here are the important details of ===:
- No implicit type coercions.
===doesn't callvalueOf()or do anything else to try to convert objects to primitives. - No value is
=== NaN. You should not use===to check forNaN, useNumber.isNaN()instead. - Object comparison is by reference - two different objects can contain the exact same keys, but
===will still say they're different.
const obj1 = { answer: 42 };
const obj2 = { answer: 42 };
obj1 === obj2; // false
Abstract Equality With ==
The == operator uses a more complex abstract equality comparison algorithm to compare whether x and y are equal. Here's a brief overview:
- If
xandyare the same type, check ifx === y. - If
xandyare both eithernullorundefined, returntrue. - If
xis a number andyis a string, convertyto a number and then compare using===. Similarly, ifxis a boolean or string, andyis a number, convertxto a number. - If
xoryis a boolean, convert the other value of a number and compare them. - If
xis an object andyis a symbol, string, or number, try to convertxto a primitive usingvalueOf()and then compare using===.
Abstract equality comparison is responsible for many of the strange edge cases that JavaScript is so famous for.
' ' == 0; // true
' ' == false; // true
({ valueOf: () => 42 }) == 42; // true
({ valueOf: () => 0 }) == false; // true
In general, you should always use === rather than == unless you're sure
you know what you're doing. There is one neat functional use for ==: checking for null or undefined (so-called nullish values) with a single check:
// Only true if `v === null` or `v === undefined`
v == null;
// Equivalent:
v === null || v === undefined;
Checking if v == null is a more concise way of checking if v is strictly
equal to null or undefined. You may choose to do this if you're a more
advanced JavaScript developer, but there is no harm in always using ===.
ESLint has a rule to disallow == unless the right hand side is null,