In JavaScript, every value has an inherent boolean value of either true or false. When you use a non-boolean value in a boolean context (like an if statement), JavaScript automatically converts it. Understanding which values are "truthy" and which are "falsy" is crucial for writing effective conditional logic and avoiding common bugs. Let's master this fundamental concept!
What Are Truthy and Falsy Values?
In boolean contexts (like conditions), JavaScript converts values to either true or false:
- Falsy values: Values that convert to false
- Truthy values: Values that convert to true
Key Insight: There are only 6 falsy values in JavaScript. Everything else is truthy!
// These values are used in boolean context
if (value) {
// Code runs if value is truthy
}
// JavaScript converts value to boolean
// Same as:
if (Boolean(value)) {
// Code runs if Boolean(value) === true
}The 6 Falsy Values
Memorize these—there are only 6 values that JavaScript considers false in boolean context:
The Complete List of Falsy Values:
false- The boolean false0- The number zero""or''- Empty stringnull- Intentional absence of valueundefined- Uninitialized valueNaN- Not a Number
Testing Falsy Values
// Test each falsy value
console.log("=== Falsy Values ===");
if (false) {
console.log("This won't run");
}
console.log("false is falsy:", Boolean(false)); // false
if (0) {
console.log("This won't run");
}
console.log("0 is falsy:", Boolean(0)); // false
if ("") {
console.log("This won't run");
}
console.log("Empty string is falsy:", Boolean("")); // false
if (null) {
console.log("This won't run");
}
console.log("null is falsy:", Boolean(null)); // false
if (undefined) {
console.log("This won't run");
}
console.log("undefined is falsy:", Boolean(undefined)); // false
if (NaN) {
console.log("This won't run");
}
console.log("NaN is falsy:", Boolean(NaN)); // falseImportant Notes About Falsy Values
// Only the NUMBER 0 is falsy
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false (negative zero)
// But other numbers are truthy!
console.log(Boolean(1)); // true
console.log(Boolean(-1)); // true
console.log(Boolean(0.1)); // true
// Only EMPTY string is falsy
console.log(Boolean("")); // false
// All non-empty strings are truthy (even "0" and "false")
console.log(Boolean("0")); // true
console.log(Boolean("false")); // true
console.log(Boolean(" ")); // true (space is a character!)
// Both null and undefined are falsy
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // falseTruthy Values (Everything Else!)
If a value is not one of the 6 falsy values, it's truthy. This includes:
Examples of Truthy Values:
- Numbers: Any number except 0 (including negative numbers, decimals, Infinity)
- Strings: Any non-empty string (including "0", "false", " ")
- Objects: All objects, including empty ones
{} - Arrays: All arrays, including empty ones
[] - Functions: All functions
- Dates: All date objects
- Boolean true: Obviously!
// All numbers except 0
console.log(Boolean(1)); // true
console.log(Boolean(-1)); // true
console.log(Boolean(0.1)); // true
console.log(Boolean(100)); // true
console.log(Boolean(-999)); // true
console.log(Boolean(Infinity)); // true
// All non-empty strings
console.log(Boolean("hello")); // true
console.log(Boolean("0")); // true (string, not number!)
console.log(Boolean("false")); // true (string, not boolean!)
console.log(Boolean(" ")); // true (contains space)
// Objects and arrays (even empty!)
console.log(Boolean({})); // true
console.log(Boolean([])); // true
console.log(Boolean([1, 2, 3])); // true
console.log(Boolean({ a: 1 })); // true
// Functions
console.log(Boolean(function(){})); // true
// Dates
console.log(Boolean(new Date())); // true
// Special values
console.log(Boolean(true)); // true (obviously)Common Gotchas:
- Empty array
[]is truthy (not falsy!) - Empty object
{}is truthy (not falsy!) - String
"0"is truthy (number 0 is falsy) - String
"false"is truthy (boolean false is falsy) - String with space
" "is truthy (empty string is falsy)
Testing for Truthy/Falsy
Using Boolean() Function
// Explicit conversion to boolean
console.log(Boolean("hello")); // true
console.log(Boolean("")); // false
console.log(Boolean(42)); // true
console.log(Boolean(0)); // false
// Test any value
let value = "test";
if (Boolean(value)) {
console.log("Truthy");
} else {
console.log("Falsy");
}Using Double NOT (!!) Operator
// Convert to boolean with !!
console.log(!!"hello"); // true
console.log(!!""); // false
console.log(!!42); // true
console.log(!!0); // false
console.log(!![]); // true
console.log(!!null); // false
// How it works:
// First ! converts to boolean and inverts
// Second ! inverts back to original truthiness
let value = "test";
let isTruthy = !!value;
console.log(isTruthy); // trueDirect Testing in Conditions
// You don't need Boolean() in if statements
let username = "John";
// JavaScript automatically converts
if (username) {
console.log("Has username"); // Executes
}
// Same as:
if (Boolean(username)) {
console.log("Has username");
}
// Testing multiple values
let values = [0, "", null, undefined, NaN, false, "hello", 42, [], {}];
values.forEach(val => {
if (val) {
console.log(`${val} is truthy`);
} else {
console.log(`${val} is falsy`);
}
});Truthy and Falsy Values Inspector
See the variables, their types, and values in real-time
let falsyNum = 0;
let truthyNum = 42;
let emptyStr = "";
let truthyStr = "hello";
let nullVal = null;
let undefVal = undefined;
let nanVal = NaN;
let emptyArr = [];
let emptyObj = {};
let boolTrue = true;
let boolFalse = false;No variables detected. Declare some variables in the code above.
let, const, or var keywords.Practical Uses of Truthy/Falsy
1. Default Values
// Set default if value is falsy
let username = "";
let displayName = username || "Guest";
console.log(displayName); // "Guest"
username = "John";
displayName = username || "Guest";
console.log(displayName); // "John"
// Function parameters
function greet(name) {
name = name || "Guest";
console.log(`Hello, ${name}!`);
}
greet(); // "Hello, Guest!"
greet("Alice"); // "Hello, Alice!"
// Or use default parameters (modern way)
function greetModern(name = "Guest") {
console.log(`Hello, ${name}!`);
}2. Checking for Existence
// Check if variable exists and has value
let user = { name: "John", age: 25 };
if (user.name) {
console.log("User has name:", user.name);
}
if (user.email) {
console.log("User has email:", user.email); // Won't execute
}
// Check array length
let items = [];
if (items.length) {
console.log("Has items");
} else {
console.log("Empty array"); // Executes
}
items = [1, 2, 3];
if (items.length) {
console.log("Has items"); // Executes
}3. Guard Clauses
function processUser(user) {
// Guard: return early if no user
if (!user) {
console.log("No user provided");
return;
}
// Guard: return early if no name
if (!user.name) {
console.log("User has no name");
return;
}
// Main logic
console.log("Processing user:", user.name);
}
processUser(null); // "No user provided"
processUser({}); // "User has no name"
processUser({ name: "John" }); // "Processing user: John"4. Conditional Execution
// Execute function if condition is truthy
let shouldLog = true;
shouldLog && console.log("Logging..."); // Executes
shouldLog = false;
shouldLog && console.log("Won't log"); // Doesn't execute
// Call function if it exists
let callback = function() {
console.log("Callback executed");
};
callback && callback(); // Executes
callback = null;
callback && callback(); // Doesn't execute (no error)Common Pitfalls and Bugs
1. Zero is Falsy
// PROBLEM: Zero is falsy
let score = 0;
if (score) {
console.log("Has score"); // Won't execute!
}
// SOLUTION: Check explicitly
if (score !== null && score !== undefined) {
console.log("Has score"); // Executes
}
// Or check type
if (typeof score === "number") {
console.log("Has score"); // Executes
}
// Or check >= 0 if you know it's a number
if (score >= 0) {
console.log("Has score"); // Executes
}2. Empty String is Falsy
// PROBLEM: Empty string is falsy
let name = "";
if (name) {
console.log("Has name"); // Won't execute
}
// SOLUTION: Check length if you want to allow empty strings
if (name !== null && name !== undefined) {
console.log("Name is defined:", name); // Executes
}
// Or check if it's a string
if (typeof name === "string") {
console.log("Name is string:", name); // Executes
}3. Empty Array/Object is Truthy
// PROBLEM: Empty arrays are truthy
let items = [];
if (items) {
console.log("Has items"); // Executes! (array is truthy)
}
// SOLUTION: Check length
if (items.length > 0) {
console.log("Has items"); // Won't execute
}
// PROBLEM: Empty objects are truthy
let user = {};
if (user) {
console.log("Has user"); // Executes! (object is truthy)
}
// SOLUTION: Check properties
if (Object.keys(user).length > 0) {
console.log("User has properties"); // Won't execute
}
// Or check specific properties
if (user.name) {
console.log("Has name"); // Won't execute
}4. String "0" is Truthy
// PROBLEM: String "0" is truthy
let value = "0"; // String from input
if (value) {
console.log("Has value"); // Executes!
}
// SOLUTION: Convert to number if comparing
if (Number(value)) {
console.log("Non-zero value"); // Won't execute
}
// Or check explicitly
if (value !== "0" && value !== "") {
console.log("Has non-zero value");
}5. NaN is Falsy But !== NaN
// NaN is falsy
let result = NaN;
if (result) {
console.log("Has result"); // Won't execute
}
// But NaN !== NaN !
console.log(NaN === NaN); // false (!)
console.log(NaN !== NaN); // true (!!)
// Use isNaN() or Number.isNaN()
if (isNaN(result)) {
console.log("Result is NaN"); // Executes
}
// Number.isNaN() is more strict (preferred)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("hello")); // false
console.log(isNaN(NaN)); // true
console.log(isNaN("hello")); // true (converts to NaN first)Practical Examples
Example 1: Form Validation
function validateForm(data) {
let errors = [];
// Check each field (truthy/falsy check)
if (!data.username) {
errors.push("Username is required");
}
if (!data.email) {
errors.push("Email is required");
}
if (!data.age) {
errors.push("Age is required");
}
// Return errors if any, or null if valid
return errors.length ? errors : null;
}
// Test with incomplete data
let form1 = { username: "john", email: "", age: 0 };
console.log(validateForm(form1));
// ["Email is required", "Age is required"]
// Note: age: 0 is falsy but might be valid!
// Better validation
function validateFormBetter(data) {
let errors = [];
if (!data.username || data.username.trim() === "") {
errors.push("Username is required");
}
if (!data.email || data.email.trim() === "") {
errors.push("Email is required");
}
// Check explicitly for age (0 might be valid)
if (data.age === null || data.age === undefined) {
errors.push("Age is required");
}
return errors.length ? errors : null;
}
console.log(validateFormBetter(form1));
// ["Email is required"]
// Now correctly accepts age: 0Example 2: Safe Property Access
function getUserCity(user) {
// Multiple levels of checking
if (user && user.address && user.address.city) {
return user.address.city;
}
return "Unknown";
}
// Test various scenarios
console.log(getUserCity(null));
// "Unknown"
console.log(getUserCity({}));
// "Unknown"
console.log(getUserCity({ address: {} }));
// "Unknown"
console.log(getUserCity({ address: { city: "New York" } }));
// "New York"
// Modern alternative: Optional chaining (ES2020)
function getUserCityModern(user) {
return user?.address?.city || "Unknown";
}
console.log(getUserCityModern(null));
// "Unknown"Example 3: Default Configuration
function createConfig(options) {
// Set defaults for falsy values
let config = {
theme: options.theme || "light",
fontSize: options.fontSize || 16,
autoSave: options.autoSave !== false, // Default true
notifications: options.notifications !== false,
maxItems: options.maxItems || 10
};
return config;
}
// With some options
console.log(createConfig({ theme: "dark", fontSize: 18 }));
// { theme: "dark", fontSize: 18, autoSave: true, notifications: true, maxItems: 10 }
// With empty object
console.log(createConfig({}));
// { theme: "light", fontSize: 16, autoSave: true, notifications: true, maxItems: 10 }
// With explicit false
console.log(createConfig({ autoSave: false, notifications: false }));
// { theme: "light", fontSize: 16, autoSave: false, notifications: false, maxItems: 10 }Truthy/Falsy Explorer
Test different values and see their truthiness
console.log() to see your output in the console above.Key Takeaways
- Only 6 falsy values: false, 0, "", null, undefined, NaN
- Everything else is truthy (including [], , "0", "false", " ")
- Use
Boolean(value)or!!valueto test truthiness - Be careful with 0 and empty strings—they're falsy
- Empty arrays and objects are truthy (check length/properties)
- String "0" is truthy, number 0 is falsy
- Use explicit checks when 0 or "" are valid values
- Truthy/falsy is great for default values and guard clauses
||operator returns first truthy value&&operator returns first falsy value or last value
What's Next?
You now understand how JavaScript treats values as true or false in boolean contexts! This knowledge is essential for writing effective conditional logic and avoiding common bugs.
In the next lesson, we'll explore Logical Operators and Short-Circuiting—diving deeper into how &&, ||, and ! work, and learning advanced patterns like short-circuit evaluation that leverages truthy/falsy values for cleaner code!
💪 Practice Challenge:
Before moving on, try creating:
- A function that safely accesses nested object properties using truthy/falsy checks
- A form validator that handles 0 and empty strings correctly
- A configuration merger that uses truthy/falsy for defaults
- A function that filters out falsy values from an array
- A debug helper that logs the truthiness of different test values