Logical Operators
Logical operators allow you to combine multiple conditions and create more complex decision-making logic. They’re essential for writing realistic programs that check multiple criteria.
What are Logical Operators?
Operators that work with boolean values (true and false) to produce a new boolean result:
const age = 25;
const hasLicense = true;
// Can drive if both conditions are true
if (age >= 18 && hasLicense) {
console.log('You can drive');
}
There are three main logical operators:
&&(AND)||(OR)!(NOT)
AND Operator (&&)
Returns true only if both conditions are true:
true && true // true
true && false // false
false && true // false
false && false // false
Basic Example
const age = 25;
const hasLicense = true;
if (age >= 18 && hasLicense) {
console.log('You can drive');
} else {
console.log('You cannot drive');
}
// Output: You can drive (both conditions are true)
Multiple Conditions
const age = 30;
const hasExperience = true;
const hasReferences = true;
if (age >= 25 && hasExperience && hasReferences) {
console.log('Qualified for senior position');
}
// All three must be true
Practical Example: Form Validation
const username = 'alice';
const password = 'secret123';
const agreeToTerms = true;
if (username.length > 0 && password.length >= 8 && agreeToTerms) {
console.log('Form is valid');
} else {
console.log('Please fill all required fields');
}
OR Operator (||)
Returns true if at least one condition is true:
true || true // true
true || false // true
false || true // true
false || false // false
Basic Example
const isWeekend = false;
const isHoliday = true;
if (isWeekend || isHoliday) {
console.log('No work today!');
} else {
console.log('Time to work');
}
// Output: No work today! (at least one is true)
Multiple Conditions
const paymentMethod = 'credit card';
if (paymentMethod === 'credit card' ||
paymentMethod === 'debit card' ||
paymentMethod === 'PayPal') {
console.log('Payment method accepted');
}
Practical Example: Access Control
const userRole = 'moderator';
if (userRole === 'admin' || userRole === 'moderator') {
console.log('Access granted to moderation tools');
} else {
console.log('Access denied');
}
NOT Operator (!)
Inverts a boolean value (true becomes false, false becomes true):
!true // false
!false // true
Basic Example
const isLoggedIn = false;
if (!isLoggedIn) {
console.log('Please log in');
}
// Output: Please log in (not false = true)
Checking for False Conditions
const hasError = false;
if (!hasError) {
console.log('Everything is working fine');
}
const isEmpty = false;
if (!isEmpty) {
console.log('List has items');
}
Double NOT (!!)
Converts any value to boolean:
const username = 'alice';
!!username // true (non-empty string)
!!'hello' // true
!!'' // false (empty string)
!!0 // false
!!42 // true
Combining Operators
Mix AND, OR, and NOT for complex logic:
AND + OR
const age = 25;
const isStudent = false;
const isRetiree = false;
// Discount for students OR retirees
if (age >= 18 && (isStudent || isRetiree)) {
console.log('Eligible for discount');
}
Parentheses matter! They control the order of evaluation:
// Without parentheses (wrong)
if (age >= 18 && isStudent || isRetiree) {
// Interpreted as: (age >= 18 && isStudent) || isRetiree
}
// With parentheses (correct)
if (age >= 18 && (isStudent || isRetiree)) {
// First checks (isStudent || isRetiree), then && with age
}
Complex Example: Ticket Pricing
const age = 15;
const isStudent = true;
const isWeekday = true;
// Full price for adults on weekends
// Discounted for children OR students on weekdays
if ((age < 18 || isStudent) && isWeekday) {
console.log('Discounted ticket: $8');
} else {
console.log('Full price ticket: $15');
}
// Output: Discounted ticket: $8
Short-Circuit Evaluation
Logical operators stop evaluating as soon as the result is determined:
AND (&&) Short-Circuit
Stops at first false:
false && console.log('This never runs');
// Nothing logged (stops at false)
true && console.log('This runs');
// Logs: This runs
const user = null;
const name = user && user.name; // null (stops at null)
// Prevents error from accessing null.name
OR (||) Short-Circuit
Stops at first true:
true || console.log('This never runs');
// Nothing logged (stops at true)
false || console.log('This runs');
// Logs: This runs
Default Values with OR
const username = '';
const displayName = username || 'Guest';
console.log(displayName); // 'Guest'
const userAge = 0;
const age = userAge || 18;
console.log(age); // 18 (0 is falsy!)
Nullish Coalescing (??)
Returns right side only if left is null or undefined (not all falsy values):
const userAge = 0;
// With OR (wrong)
const age1 = userAge || 18;
console.log(age1); // 18 (0 is falsy)
// With ?? (correct)
const age2 = userAge ?? 18;
console.log(age2); // 0 (0 is not null/undefined)
const username = '';
const name1 = username || 'Guest'; // 'Guest' (empty string is falsy)
const name2 = username ?? 'Guest'; // '' (empty string is not null/undefined)
When to use:
- Use
||for default values with any falsy value - Use
??for defaults only with null/undefined
const config = {
timeout: 0,
retries: null
};
const timeout = config.timeout || 5000; // 5000 (0 is falsy)
const retries = config.retries ?? 3; // 3 (null)
const timeoutCorrect = config.timeout ?? 5000; // 0 (correct!)
Common Patterns
1. Range Checking
const score = 75;
if (score >= 60 && score <= 100) {
console.log('Passing score');
}
const hour = 14;
if (hour >= 9 && hour < 17) {
console.log('Office is open');
}
2. Multiple Valid Options
const fileType = 'jpg';
if (fileType === 'jpg' || fileType === 'png' || fileType === 'gif') {
console.log('Valid image format');
}
// Or use array.includes()
if (['jpg', 'png', 'gif'].includes(fileType)) {
console.log('Valid image format');
}
3. Validation with Multiple Checks
const email = 'user@example.com';
const password = 'myPassword123';
const isValidEmail = email.includes('@') && email.includes('.');
const isValidPassword = password.length >= 8;
if (isValidEmail && isValidPassword) {
console.log('Registration successful');
} else {
console.log('Invalid credentials');
}
4. Role-Based Access
const userRole = 'editor';
const resourceOwner = 'alice';
const currentUser = 'alice';
const canEdit = userRole === 'admin' ||
userRole === 'editor' ||
currentUser === resourceOwner;
if (canEdit) {
console.log('Edit access granted');
}
5. Safe Property Access
const user = null;
// Without short-circuit (error!)
// const name = user.name; // Error: Cannot read property 'name' of null
// With short-circuit (safe)
const name = user && user.name;
console.log(name); // null (no error)
// Even safer with optional chaining
const name2 = user?.name;
console.log(name2); // undefined
Operator Precedence
Order of evaluation (highest to lowest):
!(NOT)&&(AND)||(OR)
// Without parentheses
true || false && false
// Evaluates as: true || (false && false)
// Result: true
// With parentheses for clarity
(true || false) && false
// Result: false
Best Practice: Use parentheses for clarity:
// Unclear
if (age >= 18 && hasLicense || hasPermit)
// Clear
if ((age >= 18 && hasLicense) || hasPermit)
Best Practices
✅ DO:
- Use parentheses for complex conditions
- Keep conditions readable (split into variables if needed)
- Use
??for null/undefined defaults - Use short-circuit evaluation for safe access
// Good - clear and readable
const isEligible = age >= 18 && hasLicense;
const hasSpecialPermit = isStudent || isSenior;
if (isEligible || hasSpecialPermit) {
grantAccess();
}
// Good - safe property access
const userName = user && user.name;
// Good - nullish coalescing for config
const timeout = config.timeout ?? 3000;
❌ DON’T:
- Write overly complex conditions in one line
- Confuse
||with?? - Forget that
&&and||return values, not just booleans - Ignore operator precedence
// Bad - too complex
if (age >= 18 && age < 65 && (isStudent || isTeacher) && !isSuspended || isAdmin)
// Bad - using || with 0 or empty string
const count = items.length || 0; // Fine, but...
const count = items.length ?? 0; // Better (explicit about null/undefined)
Truthy and Falsy with Logical Operators
Remember these values are falsy:
false,0,'',null,undefined,NaN
Everything else is truthy:
'hello' && 'world' // 'world' (both truthy, returns last)
0 && 'hello' // 0 (first is falsy)
'hello' || 'world' // 'hello' (first is truthy)
0 || 'hello' // 'hello' (first is falsy)
// Practical use
const message = errorMessage || 'No errors';
const value = userInput || defaultValue;
Summary
| Operator | Meaning | Example | Returns |
|---|---|---|---|
&& |
AND | true && true |
true (both must be true) |
|| |
OR | true || false |
true (at least one true) |
! |
NOT | !true |
false (inverts) |
?? |
Nullish | null ?? 'default' |
'default' (only for null/undefined) |
Precedence: ! → && → ||
Short-circuit:
&&stops at first falsy||stops at first truthy
Key Concepts:
- Use
&&when all conditions must be true - Use
||when any condition being true is enough - Use
!to check for false/opposite conditions - Use
??for null/undefined defaults (not all falsy values)
Next Article: Loops