The equal sign in JavaScript is not one thing — it is three entirely different operators with three entirely different behaviors. Get them confused and you will spend hours debugging a condition that looks correct but silently evaluates the wrong way. This guide explains every equality and comparison operator in JS, from the humble assignment = to triple equals in JavaScript, the not equal variants, and all the relational operators — with real-world examples, a type-coercion truth table, and a practical walkthrough of catching equality bugs with a visual diff tool.

= == === Assignment Loose Equality Strict Equality Stores a value into a variable Compares values with type coercion Compares value AND type — no coercion x = 5 '5' == 5 '5' === 5 stores 5 true false Not a boolean coerces types Recommended default
The three equal-sign operators: assignment (=), loose equality (==), and strict equality (===).

Why JavaScript Has Three Equal Signs

Most programming languages use = for assignment and == for equality. JavaScript inherited that convention but added a third operator — === — to fix a design decision that caused endless confusion: implicit type coercion in ==.

When JavaScript was created in 1995, == was designed to be "helpful" by automatically converting values to compatible types before comparing. That flexibility turned out to produce baffling results: 0 == false is true, '' == 0 is true, and null == undefined is true. ECMAScript 3 (1999) introduced === — strict equality — as an escape hatch: it never coerces types, so it behaves predictably.

Today, the ECMAScript specification (maintained at tc39.es) defines four equality algorithms: Abstract Equality (==), Strict Equality (===), SameValue (Object.is()), and SameValueZero (used internally by Map, Set, and Array.includes()). For day-to-day coding, you only need to master == and === to compare JS values confidently.

The Single Equal Sign: Assignment, Not Comparison

A single = is the assignment operator. It sets the left-hand side variable to the value on the right. It is not a comparison operator and never produces a boolean result on its own — it evaluates to the assigned value.

// Assignment — stores 42 into the variable
let score = 42;

// Common bug: assignment inside a condition
if (score = 100) {
  // This ALWAYS runs — = returns 100 (truthy)
  console.log("Score set to 100");
}

// Correct: use == or === for comparison
if (score === 100) {
  console.log("Score is 100");
}

Accidentally writing = instead of == or === inside a condition is one of the most common JavaScript bugs. Modern linters and static analysis tools flag this pattern automatically (ESLint rule: no-cond-assign).

JavaScript also has compound assignment operators that combine arithmetic with assignment: +=, -=, *=, /=, %=, **=, &&=, ||=, and ??=. These are all assignment operators, not comparison operators.

Loose Equality (==): How Type Coercion Works

How == Compares: Abstract Equality Algorithm a == b Same type? Yes Strict compare No null or undefined? Yes → true No Boolean involved? Yes bool → Number restart No → coerce str/obj to Number, restart Compare as Numbers
Simplified flowchart of the Abstract Equality Comparison algorithm used by ==.

The == operator performs the Abstract Equality Comparison algorithm defined in the ECMAScript specification (section 7.2.15 in ES2025). The algorithm is recursive and can be summarized in five steps:

  1. Same type? If both operands have the same type, fall through to strict comparison rules.
  2. null / undefined? null == undefined and undefined == null are always true. Neither equals anything else with ==.
  3. Number vs string? The string is converted to a number: '3' == 33 == 3true.
  4. Boolean involved? The boolean is converted to a number first: true1, false0.
  5. Object vs primitive? The object's valueOf() or toString() is called to produce a primitive, then comparison restarts.
// Type coercion in action
console.log(0 == false);        // true  — false coerces to 0
console.log('' == false);       // true  — both coerce to 0
console.log(null == undefined); // true  — special rule
console.log(null == false);     // false — null only equals undefined
console.log('1' == 1);          // true  — '1' coerces to 1
console.log([] == false);       // true  — [] → '' → 0, false → 0
console.log('' == 0);           // true  — '' coerces to 0

// These are the surprises that === prevents
console.log('1' === 1);         // false — different types, no coercion
console.log('' === false);      // false — different types
console.log(null === undefined);// false — different types

Understanding this algorithm is important when you maintain legacy codebases that use == throughout, or when you need to javascript compare values from APIs that mix strings and numbers. When in doubt, use === and convert types explicitly beforehand.

Strict Equality (===): The Safe Default

Triple equals in JavaScript=== — performs the Strict Equality Comparison algorithm (ECMAScript spec section 7.2.16). The rules are simple: if the two operands have different types, return false immediately. No coercion. No surprises. Only two edge cases exist:

  • NaN === NaN is false — NaN is the only value in JavaScript not equal to itself. Use Number.isNaN() to check for NaN.
  • +0 === -0 is true — positive and negative zero are strictly equal. Use Object.is(+0, -0) (returns false) if you need to distinguish them.
// Strict equality — type must match
console.log(1 === 1);           // true
console.log('hello' === 'hello'); // true
console.log(1 === '1');         // false — number vs string
console.log(true === 1);        // false — boolean vs number
console.log(null === null);     // true
console.log(undefined === undefined); // true
console.log(null === undefined); // false — different types

// NaN edge case
console.log(NaN === NaN);       // false!
console.log(Number.isNaN(NaN)); // true — correct way

// Object comparison — reference equality, not value
const a = { x: 1 };
const b = { x: 1 };
console.log(a === b);           // false — different references
console.log(a === a);           // true — same reference

The javascript three equals operator — also searched as triple equals javascript — is the basis for js string equality. When comparing strings, === does an exact character-by-character comparison. For more on string comparison patterns across languages, see the guide on string compare methods.

Not Equal: != vs !== in JavaScript

!= Loose Inequality — coerces types 1 != '1' false ← '1' coerced to 1 0 != false false null != undefined false 2 != '3' true !== Strict Inequality — no type coercion 1 !== '1' true ← types differ 0 !== false true null !== undefined true 2 !== '3' true vs
!= performs type coercion (mirrors ==), while !== is strict (mirrors ===).

The inequality operators mirror the equality operators exactly:

  • != — loose inequality. Performs the same type coercion as ==, then negates the result. js not equal the loose way.
  • !== — strict inequality. The negation of ===. Returns true if values differ in type or value, with no coercion. This is javascript not equal the safe way.
// Loose inequality — coercion applies
console.log(1 != '1');   // false — '1' coerces to 1, they are equal
console.log(0 != false); // false — false coerces to 0, they are equal
console.log(null != undefined); // false — special rule: they are loosely equal

// Strict inequality — no coercion
console.log(1 !== '1');  // true — number vs string, different types
console.log(0 !== false); // true — number vs boolean, different types
console.log(null !== undefined); // true — null-type vs undefined-type

// Practical: checking does not equal in javascript
const status = 'active';
if (status !== 'inactive') {
  // runs when status is anything other than the exact string 'inactive'
}

// js does not equal pattern in validation
function requireField(value) {
  if (value === null || value === undefined || value === '') {
    throw new Error('Field is required');
  }
  // Better than: if (value == null) — less explicit
}

The does not equal in javascript idiom you will see most in modern code is !== null and !== undefined. Whenever you search for js not equal syntax, remember that !== is almost always the right choice. Some codebases use value != null (loose) intentionally to catch both null and undefined in one check — this is one of the few legitimate uses of !=.

All JavaScript Comparison Operators at a Glance

Beyond equality, JavaScript provides relational comparison operators for ordering values. This table covers every operator you need to compare JS values. All comparison operators js developers use perform type coercion when the operands are of different types (except for Object.is(), which is a method, not an operator).

Operator Name Type coercion? Example Result
= Assignment N/A x = 5 Stores value
== Loose equality Yes '5' == 5 true
=== Strict equality No '5' === 5 false
!= Loose inequality Yes '5' != 5 false
!== Strict inequality No '5' !== 5 true
< Less than Yes '3' < 10 true
> Greater than Yes 10 > '3' true
<= Less than or equal Yes 5 <= 5 true
>= Greater than or equal Yes '5' >= 5 true
Object.is() SameValue equality No Object.is(NaN, NaN) true

The javascript greater than or equal to operator (>=) coerces strings to numbers when mixed with numeric operands, just like ==. This can produce surprises with string arrays: '10' >= '9' returns false because both are strings and string comparison is lexicographic ('1' < '9' in character code order). Always convert to numbers explicitly when ordering numeric strings.

For a deep dive on comparison operators js behavior with different data types — and when to use localeCompare() for human-readable ordering — the VS Code file comparison guide covers diff-based debugging workflows that complement these operator rules.

The Type Coercion Truth Table

Equality Truth Table: == vs === Expression == === Reason null == undefined true false Special rule 0 == false true false false → 0 '' == false true false both → 0 '' == 0 true false '' → 0 '1' == 1 true false '1' → 1 [] == false true false [] → '' → 0 NaN == NaN false false NaN ≠ anything null == false false false null ≠ non-null 1 === 1 true true same type + value == surprise (use === to avoid) Both true (same type+value) false result
Type coercion truth table: yellow cells are the "surprising" == results that === prevents.

The following table shows the results of == (loose equality) for the most commonly confused combinations. Every cell that shows true with == would return false with === (because the types differ). This is why javascript compare operations should default to ===.

Left Right == result === result Why
null undefined true false Special case in abstract equality
0 false true false false coerces to 0
'' false true false Both coerce to 0
'' 0 true false '' coerces to 0
'1' 1 true false '1' coerces to 1
'0' false true false '0'0, false0
[] false true false []''0
[0] 0 true false [0]'0'0
NaN NaN false false NaN is never equal to anything
null false false false null only equals undefined (loosely)
undefined false false false undefined only equals null (loosely)

MDN Web Docs maintains an interactive equality table that covers additional cases. The ECMAScript specification is authoritative: Abstract Equality Comparison (tc39.es).

Common Equality Bugs and How to Spot Them

Equality bugs are particularly dangerous because the code runs — it just runs wrong. Here are the five patterns that trip up developers most often, along with the correct fix.

Bug 1: Assignment in a Condition

// BUG: assigns 0 to count, then evaluates 0 (falsy)
while (count = 0) { ... }

// FIX: compare with ===
while (count === 0) { ... }

Bug 2: Comparing a Number to Its String Form

// API returns a string, code expects a number
const userId = getUserIdFromUrl(); // returns '42' (string)
if (userId == 42) { ... }    // works but fragile

// FIX: parse explicitly, then strict-compare
if (Number(userId) === 42) { ... }

Bug 3: Checking for null with ===

// Misses undefined — breaks if value was never set
if (response.data === null) { handleEmpty(); }

// FIX: use loose equality intentionally to catch both null and undefined
if (response.data == null) { handleEmpty(); }
// equivalent to: response.data === null || response.data === undefined

Bug 4: Comparing NaN

// NaN === NaN is always false
const parsed = parseInt('abc');
if (parsed === NaN) { ... } // never runs!

// FIX: use Number.isNaN()
if (Number.isNaN(parsed)) { handleBadInput(); }

Bug 5: Object Reference vs Value Equality

// Two objects with identical structure are NOT === equal
const config1 = { timeout: 5000 };
const config2 = { timeout: 5000 };
console.log(config1 === config2); // false — different references

// FIX: compare specific properties, or serialize for deep equality
console.log(config1.timeout === config2.timeout); // true
console.log(JSON.stringify(config1) === JSON.stringify(config2)); // true (for simple objects)

These same patterns appear when you review pull requests or audit legacy code. Whether you are checking that a value js does not equal an expected default or verifying deep object equality, the challenge is that these bugs are invisible until you diff the before-and-after versions of a file side by side. Learning to spot the difference between two code revisions is the fastest way to catch these single-character bugs — and a visual diff tool becomes your fastest debugging ally.

Finding Equality Bugs with Diff Tools

Equality Bug Fix — Visual Diff BEFORE (buggy) 1 function checkAdmin(role) { 2 if (role == 'admin') { 3 grantAccess(); 4 } 5 } Problem: type coercion may grant access with value 0 or false AFTER (fixed) 1 function checkAdmin(role) { 2 if (role === 'admin') { 3 grantAccess(); 4 } 5 } Fix: strict equality ensures role must be exactly the string 'admin' diff
A single character change from == to === — visual diffs make this impossible to miss.

Reading code line by line, the difference between == and === is a single character. In a large pull request or a minified build, that one character is trivially easy to overlook. A visual diff tool makes it impossible to miss.

The Diff Checker browser extension is built on the Monaco Editor — the same engine that powers VS Code — so JavaScript syntax is highlighted correctly and operator changes are clearly visible. Here is a concrete workflow for reviewing equality changes in code:

  1. Open Diff Checker from the Chrome toolbar. The extension opens an editor with two panes in split view.
  2. Paste the old version of the function into the left pane and the new version into the right pane.
  3. Select JavaScript from the language picker for full syntax highlighting (one of 20+ supported languages including TypeScript, JSX, and TSX).
  4. Choose Smart Diff algorithm — it groups semantically related changes together and minimizes noise from whitespace differences. You can also switch to Ignore Whitespace or Classic LCS depending on the code style.
  5. Navigate changes with Alt+Down / Alt+Up to jump between each modified line. The diff statistics panel shows the count of added, removed, and modified lines plus a similarity percentage — useful for gauging how significant a refactor is.
  6. Revert individual blocks with the one-click revert icon if you spot a change that should not be there.

Because Diff Checker processes everything locally (no server uploads), this workflow is safe for proprietary codebases. The comparison history stores your last 50 sessions in IndexedDB, so you can return to a previous review without re-pasting.

The AI summary feature (powered by your own OpenAI API key) can read the diff and describe what changed in plain English — useful when reviewing an unfamiliar codebase and you need a quick explanation of why === was substituted for == in a particular block.

This visual approach pairs well with comparing files in VS Code — the two tools complement each other: VS Code for in-repo diffs during development, Diff Checker for ad-hoc comparisons of code snippets, API responses, and configuration files outside a git context.

Best Practices for JavaScript Equality

Which Equality Operator Should I Use? Comparing two values NaN or ±0 edge case? Yes Object.is() No null guard? (catch both null + undefined) Yes == null No Comparing objects/arrays? Yes _.isEqual() deep compare No === (default for everything else)
Decision tree: default to ===, use Object.is() for NaN/±0 edge cases, use == null for null guards, and use deep-equal for objects.

These rules reflect modern JavaScript conventions as codified in style guides from Airbnb, Google, and the TC39 committee:

1. Default to === for All Comparisons

The triple equals JavaScript operator is the baseline. It does not coerce types, so the result always matches what you see. ESLint's eqeqeq rule enforces this automatically.

// Enforce in .eslintrc.json
{
  "rules": {
    "eqeqeq": ["error", "always"]
  }
}

2. Use == null Only for Null/Undefined Guard

The one widely accepted use of == is the null guard: value == null returns true for both null and undefined. This is shorter and more readable than value === null || value === undefined. Document the intent with a comment if your team defaults to eqeqeq: always.

3. Convert Types Explicitly Before Comparing

When working with data from APIs, form inputs, or URL parameters, values often arrive as strings. Convert them before any comparison:

const raw = searchParams.get('page'); // '3' (string)
const page = Number(raw);            // 3 (number)
if (page === 1) { showFirstPageHint(); }

4. Use Object.is() for NaN and Signed Zero Edge Cases

Object.is(a, b) is the only operator that returns true for NaN === NaN and false for +0 === -0. Use it in math-heavy code, physics engines, or any context where these distinctions matter.

5. Deep Equality for Objects and Arrays

Neither == nor === compares object contents — both check reference identity. For structural comparison, use:

  • JSON.stringify(a) === JSON.stringify(b) for simple, serializable objects (order-dependent).
  • A deep-equal utility like _.isEqual from Lodash for complex nested structures.
  • structuredClone + === for certain use cases in modern runtimes.

6. js string equality — Always === with Optional Normalization

For js string equality, use === directly. When case or whitespace variation is possible (user input, API fields), normalize first:

const input = userInput.trim().toLowerCase();
const expected = 'admin';
if (input === expected) { grantAccess(); }

For locale-sensitive ordering (sorting names, comparing words in different languages), JavaScript's localeCompare() is the closest equivalent to javascript compareto and js compareto in Java. It returns a negative, zero, or positive number like compareTo(). See the Java string equality guide for a side-by-side comparison of the two languages' string comparison APIs.

7. Enforce with Linting and Code Review

Operator mistakes slip through code review because the difference is a single character. The javascript three equals rule should be non-negotiable in your config. Enable eqeqeq in ESLint, configure your CI pipeline to fail on violations, and use visual diff reviews for any equality-sensitive logic changes. On Linux or macOS, you can also pipe two script versions through the diff command to quickly find the difference in equality operator usage across files.

Catch Equality Bugs Before They Ship — Free

Paste two versions of your JavaScript side by side in Diff Checker and see every operator change highlighted instantly. Monaco Editor engine, JavaScript and TypeScript syntax highlighting, Smart Diff algorithm, and one-click change navigation. Runs 100% locally — no uploads, no account required.

Add to Chrome — It's Free

Frequently Asked Questions

Why use === instead of == in JavaScript?
=== (strict equality) checks both value and type without any coercion, so '1' === 1 returns false. == performs type coercion first, making '1' == 1 return true. Using === eliminates a whole class of implicit conversion bugs and makes your intent explicit. The ECMAScript specification and every major JavaScript style guide recommend === as the default.
What is the difference between == and === in JavaScript?
== is the loose equality operator — it converts operands to a common type before comparing (type coercion). === is the strict equality operator — it never coerces; if the types differ, it immediately returns false. The practical result: null == undefined is true while null === undefined is false. For predictable code, prefer === everywhere except the intentional null guard pattern.
How does type coercion work in JavaScript ==?
JavaScript follows the Abstract Equality Comparison algorithm (ECMAScript section 7.2.15). In brief: if types differ, JS converts one or both values — usually to Number. Booleans convert to 0/1, strings are parsed as numbers, and objects call valueOf()/toString(). The exceptions: null and undefined only equal each other (loosely), and NaN is never equal to anything including itself.
What does !== mean in JavaScript?
!== is the strict inequality operator — the negation of ===. It returns true when values differ in type or content with no coercion. 1 !== '1' is true because the types differ. The looser != coerces types before comparing, mirroring ==. In modern JavaScript, prefer !== for the same reason you prefer === over ==.
Does JavaScript have a compareTo() method like Java?
JavaScript has no built-in javascript compareto method on strings. The equivalent for ordering is String.prototype.localeCompare(), which returns a negative number, 0, or positive number — the same contract as Java's compareTo(). For sorting: arr.sort((a, b) => a.localeCompare(b)). For equality, use === directly. See the Java string equality guide for a side-by-side comparison of the two APIs.
How do I compare strings for equality in JavaScript?
Use === for exact js string equality: 'hello' === 'hello' returns true. For case-insensitive comparison, normalize first: a.toLowerCase() === b.toLowerCase(). For Unicode normalization (accented characters, ligatures), call a.normalize('NFC') === b.normalize('NFC') before comparing. Never rely on == for string comparison — it is slower and adds no useful coercion behavior when both operands are already strings.
What is greater than or equal to in JavaScript?
The javascript greater than or equal to operator is >=. It returns true when the left operand is greater than or equal to the right. Like all relational operators, it coerces types when operands differ: '5' >= 5 is true. Watch out for string comparisons: '10' >= '9' is false because string comparison is lexicographic. Convert to numbers explicitly when ordering numeric strings.