Comparison & Logical Operators

Comparison operators ask questions — is this bigger, are these equal? — and answer with true or false. Logical operators combine those answers. Together they're the building blocks of every decision a program makes.

Comparison operators

JS compare.js
const age = 20;

console.log(age > 18);
console.log(age < 18);
console.log(age >= 20);
console.log(age <= 19);
console.log(age === 20);
console.log(age !== 20);
Output
true
false
true
false
true
false

Strict (===) vs loose (==) equality

JavaScript has two equality operators. === is strict: values must have the same type and the same value. == is loose: it converts types first, with rules that are hard to remember:

JS equality.js
console.log(5 === "5");
console.log(5 == "5");
console.log(0 == "");
console.log(0 == false);
console.log(null == undefined);
console.log(null === undefined);
Output
false
true
true
true
true
false

Always use === and !==. The only common exception is value == null, which is a deliberate shortcut for "null or undefined".

Note: NaN is not equal to anything, including itself — NaN === NaN is false. Use Number.isNaN(value) to test for it.

Comparing strings

Strings are compared character by character using their Unicode values, which is alphabetical for simple lowercase text — but uppercase letters come before all lowercase ones:

JS strings.js
console.log("apple" < "banana");
console.log("Zebra" < "apple");
console.log("10" < "9");
console.log(10 < 9);
Output
true
true
true
false

"10" < "9" is true because the character "1" comes before "9". Make sure numbers are numbers before comparing them. For human-friendly sorting, use localeCompare (lesson 32).

Logical operators

OperatorNameTrue when…
&&ANDboth sides are true
||ORat least one side is true
!NOTflips true to false and back
JS logic.js
const hasTicket = true;
const isVip = false;
const age = 16;

console.log(hasTicket && age >= 18);
console.log(hasTicket || isVip);
console.log(!isVip);
console.log((hasTicket && age >= 18) || isVip);
Output
false
true
true
false

&& binds more tightly than ||, but parentheses make combined conditions much easier to read.

Short-circuiting

Logical operators stop as soon as the answer is known. && stops at the first falsy value; || stops at the first truthy one. They also return the value where they stopped — not necessarily true or false:

JS short-circuit.js
console.log("cat" && "dog");
console.log("" && "dog");
console.log("" || "default");
console.log("chosen" || "default");

const user = null;
console.log(user && user.name);
Output
dog

default
chosen
null

The second line prints an empty string. user && user.name is a classic guard: if user is missing, the expression stops and never tries to read .name. "Truthy" and "falsy" are explained fully in lesson 19.

Nullish coalescing: ??

|| is often used for default values, but it treats 0, "" and false as missing. ?? only falls back when the left side is null or undefined:

JS nullish.js
const volume = 0;

console.log(volume || 50);
console.log(volume ?? 50);
console.log(undefined ?? 50);
Output
50
0
50

Use ?? for defaults whenever 0, "" or false are valid values.

Optional chaining: ?.

?. reads a property only if the thing before it exists, returning undefined instead of crashing:

JS optional.js
const order = { customer: { name: "Kai" } };
const emptyOrder = {};

console.log(order.customer?.name);
console.log(emptyOrder.customer?.name);
console.log(emptyOrder.customer?.name ?? "Guest");
Output
Kai
undefined
Guest

Logical assignment

JS logical-assign.js
const settings = { theme: "", retries: 0 };

settings.theme ||= "light";
settings.retries ??= 3;
settings.language ??= "en";

console.log(settings);
Output
{ theme: 'light', retries: 0, language: 'en' }

a ||= b assigns only if a is falsy; a ??= b only if a is null/undefined; a &&= b only if a is truthy.

Try it yourself

Try it yourself
Console output