Learn how to compare values and combine conditions to produce
true or false — the foundation of every
decision your code will ever make.
Comparison operators compare two values and return a boolean
— e.g. is a greater than b? Are they equal?
Logical operators combine multiple boolean expressions —
e.g. is condition A and condition B both true?
Together they power every if statement, loop condition, and
decision in JavaScript. Understanding the difference between ==
and === in particular is one of the most important fundamentals
in the language.
Think of these operators as questions JavaScript asks before deciding what to do next:
let a = 10;
let b = "10";
console.log(a == b); // true — same value, type ignored
console.log(a === b); // false — different types (number vs string)
console.log(a != b); // false — values are equal
console.log(a !== b); // true — types are different
console.log(10 > 5); // true
console.log(10 < 5); // false
console.log(10 >= 10); // true
console.log(10 <= 9); // false
== checks only value — it converts types before comparing (loose equality)=== checks value and type — no conversion (strict equality, always prefer this)!== is the strict "not equal" — returns true when value or type differslet age = 20;
let hasID = true;
// && (AND) — both must be true
console.log(age > 18 && hasID); // true (both true)
console.log(age > 18 && !hasID); // false (second is false)
// || (OR) — at least one must be true
console.log(age < 18 || hasID); // true (second is true)
console.log(age < 18 || false); // false (both false)
// ! (NOT) — flips the boolean
console.log(!hasID); // false
console.log(!false); // true
&& (AND) — the result is true only when every condition is true|| (OR) — the result is true when at least one condition is true! (NOT) — inverts the boolean: !true === false, !false === true// && stops as soon as it finds false
console.log(false && console.log("A")); // "A" never prints!
// || stops as soon as it finds true
console.log(true || console.log("B")); // "B" never prints!
// Practical use: default values
let userName = null;
let displayName = userName || "Guest"; // if userName is falsy, use "Guest"
console.log(displayName);
false && anything — the right side is never reached because the result is already falsetrue || anything — the right side is never reached because the result is already true|| default value pattern is widely used to provide fallbackslet score = 75;
let attended = true;
// Pass if score >= 60 AND attended
let passed = score >= 60 && attended;
console.log("Passed:", passed);
// Grade logic
let isA = score >= 90;
let isB = score >= 75 && score < 90;
let isC = score >= 60 && score < 75;
console.log("A grade:", isA);
console.log("B grade:", isB);
console.log("C grade:", isC);
&& and ||Think of a club's entry check — every rule maps directly to an operator:
Click ▶ Preview, enter your age and check the ID box, then
click Check — watch && and || decide the
outcome in real time.
<!DOCTYPE html>
<html>
<head><title>Operators Demo</title></head>
<body style="font-family:sans-serif;padding:24px;background:#f8f9fa">
<h2>Check Eligibility</h2>
<label>Age:
<input id="ageInput" type="number" placeholder="Enter age"
style="padding:6px 10px;border:1px solid #ccc;border-radius:6px;
font-size:1rem;width:130px;margin-left:8px">
</label><br><br>
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input id="idCheck" type="checkbox"
style="width:16px;height:16px;cursor:pointer">
Has valid ID
</label><br>
<button onclick="checkEligibility()"
style="padding:8px 18px;background:#f7df1e;border:none;border-radius:6px;
cursor:pointer;font-weight:700;font-size:1rem">
Check
</button>
<div id="output" style="margin-top:16px;line-height:2.2;font-size:0.95rem"></div>
<script>
function checkEligibility() {
let age = Number(document.getElementById("ageInput").value);
let hasID = document.getElementById("idCheck").checked;
if (!age) {
document.getElementById("output").innerHTML =
"<b style='color:red'>Please enter an age.</b>";
return;
}
let isAdult = age >= 18;
let canEnter = isAdult && hasID;
let partialPass = isAdult || hasID;
document.getElementById("output").innerHTML =
"<b>Age (>= 18):</b> " + isAdult + "<br>" +
"<b>Has ID:</b> " + hasID + "<br>" +
"<b>Can enter (age AND id):</b> <b style='color:" +
(canEnter ? "green" : "red") + "'>" + canEnter + "</b><br>" +
"<b>Partial pass (age OR id):</b> " + partialPass;
}
</script>
</body>
</html>
let num = 60;
// Print true or false — is num greater than 50?
console.log(num > 50);
truenum to 40 and run again — confirm it prints false=== to see if num equals 50 exactlylet username = "admin";
let password = "1234";
// Use && to check both conditions at once
=== and && to check if both username and password are correctlet isLoggedIn variable and print itfalseconsole.log(5 == "5");
== performs type coercion — the string "5" is converted to the number 5 before comparing, so the values match and the result is true. This is why === is preferred.
console.log(5 === "5");
=== checks value and type. 5 is a number and "5" is a string — different types, so the result is false with no conversion.
&& operator mean?
let a = true;
let b = false;
console.log(a && b);
console.log(a || b);
&& (AND) returns true only when both operands are true. If either is false, the result is false. || (OR) returns true if at least one is true.
Always prefer === over == — loose equality causes unexpected bugs that are very hard to track down:
console.log(0 == false); // true — coercion!
console.log(0 === false); // false — correct
console.log("" == false); // true — coercion!
console.log("" === false); // false — correct
console.log(null == undefined); // true — coercion!
console.log(null === undefined); // false — correct
Use ! to toggle boolean values cleanly — a common pattern for on/off switches:
let isActive = true;
isActive = !isActive; // toggle off
console.log(isActive); // false
isActive = !isActive; // toggle on
console.log(isActive); // true
Use || for default values when a variable might be falsy — a very common real-world pattern:
let userInput = ""; // empty string — falsy
let name = userInput || "Guest";
console.log(name); // "Guest" — fallback used
let score = 0; // zero — also falsy!
let display = score || "No score yet";
console.log(display); // "No score yet" — careful with 0!
Use the nullish coalescing operator (??) when you only want to fall back on null or undefined — not on 0 or empty string:
let score = 0;
console.log(score || 100); // 100 — 0 is falsy, || replaces it
console.log(score ?? 100); // 0 — ?? only replaces null/undefined
let empty = null;
console.log(empty ?? "default"); // "default"
Operator precedence matters here — evaluate step by step, then run to confirm.
console.log(10 > 5 && 5 < 3 || true);
// Full expression: 10 > 5 && 5 < 3 || true
// Operator precedence (highest to lowest here):
// > and < evaluate first (comparison)
// && evaluates next (AND)
// || evaluates last (OR)
// Step 1: evaluate comparisons
// 10 > 5 → true
// 5 < 3 → false
// Expression now: true && false || true
// Step 2: evaluate && (higher precedence than ||)
// true && false → false
// Expression now: false || true
// Step 3: evaluate ||
// false || true → true
// Output → true
// Key takeaway:
// && binds tighter than || — the same way * binds before +
// Use parentheses to make intent explicit:
// (10 > 5 && 5 < 3) || true → same result, much clearer