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.
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
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:
- Same type? If both operands have the same type, fall through to strict comparison rules.
- null / undefined?
null == undefinedandundefined == nullare alwaystrue. Neither equals anything else with==. - Number vs string? The string is converted to a number:
'3' == 3→3 == 3→true. - Boolean involved? The boolean is converted to a number first:
true→1,false→0. - Object vs primitive? The object's
valueOf()ortoString()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 === NaNisfalse— NaN is the only value in JavaScript not equal to itself. UseNumber.isNaN()to check for NaN.+0 === -0istrue— positive and negative zero are strictly equal. UseObject.is(+0, -0)(returnsfalse) 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
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===. Returnstrueif 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
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, false → 0 |
[] | 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
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:
- Open Diff Checker from the Chrome toolbar. The extension opens an editor with two panes in split view.
- Paste the old version of the function into the left pane and the new version into the right pane.
- Select JavaScript from the language picker for full syntax highlighting (one of 20+ supported languages including TypeScript, JSX, and TSX).
- 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.
- 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.
- 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
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
_.isEqualfrom 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 FreeFrequently Asked Questions
- Why use === instead of == in JavaScript?
-
===(strict equality) checks both value and type without any coercion, so'1' === 1returnsfalse.==performs type coercion first, making'1' == 1returntrue. 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 returnsfalse. The practical result:null == undefinedistruewhilenull === undefinedisfalse. 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:nullandundefinedonly equal each other (loosely), andNaNis never equal to anything including itself. - What does !== mean in JavaScript?
-
!==is the strict inequality operator — the negation of===. It returnstruewhen values differ in type or content with no coercion.1 !== '1'istruebecause 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'scompareTo(). 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'returnstrue. For case-insensitive comparison, normalize first:a.toLowerCase() === b.toLowerCase(). For Unicode normalization (accented characters, ligatures), calla.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 returnstruewhen the left operand is greater than or equal to the right. Like all relational operators, it coerces types when operands differ:'5' >= 5istrue. Watch out for string comparisons:'10' >= '9'isfalsebecause string comparison is lexicographic. Convert to numbers explicitly when ordering numeric strings.