JavaScript
Programming
Coding
Web Development
Computer Science

Difference between == and === in JavaScript

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

JavaScript has two equality operators: == (loose equality) and === (strict equality). The == operator compares values after type coercion, while === compares both value and type without any conversion. Understanding the difference is critical for avoiding subtle bugs.

Strict Equality (===)

=== returns true only if both the value and type are identical. No type conversion occurs:

javascript
15 === 5          // true  (same value, same type)
2"5" === 5        // false (string vs number)
3true === 1       // false (boolean vs number)
4null === undefined // false (different types)
50 === false      // false (number vs boolean)
6"" === false     // false (string vs boolean)
7NaN === NaN      // false (NaN is never equal to anything)

Loose Equality (==)

== performs type coercion before comparing. JavaScript converts one or both operands to a common type:

javascript
15 == 5           // true
2"5" == 5         // true  (string "5" coerced to number 5)
3true == 1        // true  (boolean true coerced to 1)
4false == 0       // true  (boolean false coerced to 0)
5null == undefined // true (special case in the spec)
6"" == false      // true  (both coerce to 0)
7" " == 0         // true  (string " " coerces to 0)

Type Coercion Rules

When == compares different types, it follows these rules:

  1. Number vs String: The string is converted to a number
  2. Boolean vs Anything: The boolean is converted to a number (true→1, false→0)
  3. null vs undefined: They are equal to each other and nothing else
  4. Object vs Primitive: The object's valueOf() or toString() is called
javascript
1// String to Number
2"42" == 42       // true: "42" → 42
3
4// Boolean to Number
5true == 1        // true: true → 1
6false == 0       // true: false → 0
7true == "1"      // true: true → 1, "1" → 1
8
9// null and undefined
10null == undefined   // true (special case)
11null == 0           // false (null only equals undefined)
12null == ""          // false
13undefined == false  // false
14
15// Object to Primitive
16[1] == 1           // true: [1].toString() → "1" → 1
17["5"] == 5         // true: ["5"].toString() → "5" → 5

Surprising Results with ==

javascript
1// All of these are true with ==
2"" == false       // true
3"0" == false      // true
4" " == 0          // true
5[] == false       // true
6[] == 0           // true
7[[]] == 0         // true
8[null] == ""      // true
9
10// The transitive property breaks
11"" == 0           // true
120 == "0"          // true
13"" == "0"         // false! (both are strings, no coercion)

The !== and != Operators

The same distinction applies to inequality:

javascript
1// Strict inequality
25 !== "5"         // true (different types)
35 !== 5           // false
4
5// Loose inequality
65 != "5"          // false (coerced, values are equal)
75 != 5            // false

Best Practice: Always Use ===

The === operator is predictable and avoids coercion bugs:

javascript
1// BAD: subtle bugs
2if (value == null) { }        // matches both null and undefined
3if (value == 0) { }           // matches 0, "", false, null? No, but confusing
4if (response == true) { }     // matches 1, "1", etc.
5
6// GOOD: explicit and clear
7if (value === null || value === undefined) { }
8if (value === 0) { }
9if (response === true) { }

When == Is Acceptable

The only widely accepted use of == is checking for null or undefined:

javascript
1// This is a common pattern even in strict codebases
2if (value == null) {
3    // handles both null and undefined
4}
5
6// Equivalent to:
7if (value === null || value === undefined) {
8    // same behavior, more verbose
9}

ESLint Rules

Most JavaScript linters enforce strict equality:

json
1{
2    "rules": {
3        "eqeqeq": ["error", "always"]
4    }
5}

The eqeqeq rule can be configured to allow == only for null checks:

json
1{
2    "rules": {
3        "eqeqeq": ["error", "always", { "null": "ignore" }]
4    }
5}

Comparison Table

Expression=====
"5" ? 5truefalse
0 ? falsetruefalse
"" ? falsetruefalse
null ? undefinedtruefalse
NaN ? NaNfalsefalse
[1] ? 1truefalse
true ? 1truefalse

Common Pitfalls

  • Truthy/falsy confusion: == and truthy/falsy checks are different things. "0" == false is true, but "0" is truthy in a boolean context (if ("0") is true). Do not conflate them.
  • NaN equality: NaN === NaN is false. Use Number.isNaN() to check for NaN, not ===.
  • Object comparison: Both == and === compare objects by reference, not value. {a:1} === {a:1} is false because they are different objects.
  • typeof check: typeof null === "object" is true (a known JavaScript quirk). Check for null explicitly before using typeof.
  • Automatic coercion in other contexts: Coercion also happens with <, >, +, and other operators. "5" + 3 is "53" (string concatenation), not 8.

Summary

  • === (strict equality) compares value and type — no coercion, no surprises
  • == (loose equality) coerces types before comparing — can produce unexpected results
  • Always use === and !== by default
  • The only acceptable use of == is value == null to check for both null and undefined
  • Enable the eqeqeq ESLint rule to enforce strict equality in your codebase

Course illustration
Course illustration

All Rights Reserved.