Quick Overview
`==` converts types before comparing, which is how `0 == ""` ends up true. `===` compares type and value together, and that is why it is the default and `==` the deliberate exception.
A boolean represents a logical state with only two possible values: true or false. Booleans are the engine behind conditional branching in software.
When non-boolean values (like strings, numbers, or objects) are evaluated in conditional contexts (like if statements), JavaScript implicitly converts them into either truthy or falsy values. Understanding these rules prevents unexpected control flow bugs.
In JavaScript, exactly 6 values evaluate to false in a boolean context. Memorizing these 6 makes understanding conditional checks effortless:
false (The literal boolean)0 (including -0 and 0n)"" (Empty string)null (Intentional empty reference)undefined (Uninitialized variable)NaN (Not-a-Number)EVERY OTHER VALUE IN JAVASCRIPT IS TRUTHY! This includes empty arrays [], empty objects {}, and the string "false".
const userSearch = "";
if (userSearch) {
console.log("Searching...");
} else {
console.log("Please enter a search query."); // Runs because "" is falsy!
}
Loose equality (==) performs implicit type coercion before comparing values. Strict equality (===) compares both value AND data type without converting types:
console.log(0 == "0"); // true (Loose coercion! Dangerous!)
console.log(0 === "0"); // false (Strict comparison! Safe!)
console.log(null == undefined); // true
console.log(null === undefined); // false
[] == false is true!). Always default to strict equality (===).[] and {} are truthy objects! Checking if (myArray) on an empty array will evaluate to true. To check if an array is empty, check its length: myArray.length > 0.Write it yourself. The tests below run against your code.
Always use === for comparisons. Next, let's learn how to branch application execution using if, else, and ternary operators!
Primitives copy by value and objects copy by reference, so `b = a` duplicates a number but shares an object. That single distinction explains most surprise mutations in a codebase.
`const` prevents reassignment, not mutation: a `const` object's properties can still be changed. `let` is scoped to its block, while `var` is function-scoped and leaks out of loops.
Only backticks interpolate: `${user}` reads the variable, while the identical text in quotes prints literally. Strings are immutable, so every method returns a new one rather than editing in place.