Vanta Logo
SPONSOR
Automate SOC 2 & ISO 27001 compliance with Vanta. Get $1,000 off.
Published
7 min read
Up to date

Trevor I. Lasn

Staff Software Engineer, Engineering Manager

JavaScript Operators: '||' vs '&&' vs '??'

Master JavaScript logical operators with practical examples and best practices

JavaScript’s logical operators (||, &&, ??) are powerful tools that go way beyond simple true/false operations. Let’s dive into how they work, explore some clever use cases, and see how they can make your code cleaner and more elegant.

The OR Operator ||: Default Values Made Simple

The OR operator (||) is a shortcut for setting default values. It returns the first “truthy” value it finds, making it perfect for fallback values. If you’re new to truthy and falsy values, here’s a helpful guide.

JavaScript
// Basic boolean operations
true || false // returns true
false || true // returns true
false || false // returns false
// Working with different types
"hello" || "world" // returns "hello"
"" || "fallback" // returns "fallback"
null || "default" // returns "default"
undefined || 42 // returns 42

This pattern shines when setting default values:

JavaScript
// Clean default value syntax
function greet(name) {
return `Hello, ${name || 'friend'}!`;
}
// Useful for configuration objects
const config = {
port: process.env.PORT || 3000,
host: process.env.HOST || 'localhost',
timeout: process.env.TIMEOUT || 5000
};

The AND Operator &&: Elegant Conditional Execution

The AND operator (&&) is your friend for conditional execution. It returns the first “falsy” value or the last value if everything is truthy. This creates a clean way to run code conditionally.

JavaScript
// Boolean operations
true && false // returns false
true && true // returns true
false && true // returns false
// Working with values
"hello" && "world" // returns "world"
"" && "test" // returns ""
null && "anything" // returns null

The && operator in JavaScript does something subtle - it returns the last value if all conditions are true, or the first falsy value it encounters. This behavior enables two powerful patterns:

JavaScript
// Pattern 1: Single-line conditional execution
isValid && sendToServer(data);
// Under the hood, this is doing:
if (isValid) {
sendToServer(data);
}

This works because:

  • If isValid is false, && returns false and stops there
  • If isValid is true, && evaluates and returns the result of sendToServer(data)
JSX
// Pattern 2: Conditional rendering in React
return (
<div>
{isLoggedIn && <UserDashboard />}
{hasError && <ErrorMessage text={errorText} />}
</div>
);
// React processes this as:
{true && <Component />} // renders <Component />
{false && <Component />} // renders false (React ignores it)

The magic happens because:

  • React ignores false, null, and undefined in JSX
  • When isLoggedIn is true, && returns the component
  • When isLoggedIn is false, && returns false (which React ignores)

Watch Out For These Cases

JSX
// Potential gotcha with numbers
const count = 0;
return (
<div>
{count && <DisplayCount number={count} />} // Oops! Renders 0
</div>
);
// Safer version
return (
<div>
{count !== undefined && <DisplayCount number={count} />}
{/* or */}
{count >= 0 && <DisplayCount number={count} />}
</div>
);

JavaScript Operators: '||' vs '&&' vs '??'

  • Any falsy value (0, '', null, undefined, false) will short-circuit &&
  • In React, only false, null, and undefined are truly “invisible”
  • Other falsy values like 0 or '' will actually render

The Nullish Coalescing Operator ??: Smart Defaults

Think of ?? as a smarter way to set default values. Unlike || which triggers on any falsy value, ?? only triggers on null or undefined. Here’s why this difference matters:

JavaScript
// Let's see what || considers "falsy":
0 || "default" // returns "default"
"" || "default" // returns "default"
false || "default" // returns "default"
null || "default" // returns "default"
undefined || "default" // returns "default"
// Now compare with ??:
0 ?? "default" // returns 0 ✨
"" ?? "default" // returns "" ✨
false ?? "default" // returns false ✨
null ?? "default" // returns "default"
undefined ?? "default" // returns "default"

This becomes super useful when working with numbers or strings where 0 or "" are meaningful values:

JavaScript
// Working with quantities
function updateQuantity(newQuantity) {
// BAD: || turns 0 into 1
cart.quantity = newQuantity || 1; // 0 becomes 1
// GOOD: ?? keeps 0 as 0
cart.quantity = newQuantity ?? 1; // 0 stays 0
}
// Working with form inputs
function updateProfile(formData) {
// BAD: || replaces empty string with default
user.bio = formData.bio || "No bio yet"; // "" becomes "No bio yet"
// GOOD: ?? keeps empty string
user.bio = formData.bio ?? "No bio yet"; // "" stays as ""
}
// Real-world example: API response handling
function processUserData(response) {
return {
name: response.name ?? 'Anonymous',
posts: response.posts ?? [],
score: response.score ?? 0, // 0 is a valid score
bio: response.bio ?? '', // Empty bio is valid
lastLogin: response.lastLogin ?? null
};
}

The ?? operator really shines when:

  1. Working with numbers where 0 is valid
  2. Handling strings where empty string is meaningful
  3. Processing API responses where you need to distinguish between “not set” (null/undefined) and “intentionally empty” (0/"")

You can also chain it for multiple fallbacks:

JavaScript
// Multiple fallbacks while preserving 0 and ""
const username = input ?? stored ?? generated ?? 'guest';
// Useful in configuration
const config = {
timeout: process.env.TIMEOUT ?? defaultTimeout ?? 5000,
retries: process.env.RETRIES ?? settings.retries ?? 3,
path: process.env.PATH ?? defaultPath ?? ''
};

Choosing the Right Operator

Let’s look at common scenarios and which operator fits best:

  1. Need a default value? Here’s how to choose:
JavaScript
// When 0 or empty string are NOT valid values, use ||
function getName(user) {
return user.name || 'Anonymous'; // empty string becomes 'Anonymous'
// This handles all these cases:
'' || 'Anonymous' // returns 'Anonymous'
0 || 'Anonymous' // returns 'Anonymous'
null || 'Anonymous' // returns 'Anonymous'
false || 'Anonymous' // returns 'Anonymous'
}
// When 0 or empty string ARE valid values, use ??
function getQuantity(product) {
return product.quantity ?? 1; // 0 stays 0, only null/undefined become 1
// This handles the edge cases better:
0 ?? 1 // returns 0 (preserves valid zero)
'' ?? 'default' // returns '' (preserves empty string)
null ?? 1 // returns 1
undefined ?? 1 // returns 1
}
  1. Need conditional execution? Use &&
JavaScript
// The && operator is perfect when you want to:
// 1. Run code only if a condition is true
// 2. Show UI elements conditionally
// 3. Access nested properties safely
// Function calls
function processUser(user) {
// Only calls expensive function if user is premium
user.isPremium && loadPremiumFeatures(user);
// Safer than if statements for nullable objects
user?.settings?.theme && applyTheme(user.settings.theme);
}
// Error handling
function submitForm(data) {
// Multiple conditions
isValid && !isLoading && sendToServer(data);
// With error handling
isValid && handleSuccess() || handleError();
}
// React conditional rendering
function UserProfile({ user, isAdmin }) {
return (
<div>
{/* Basic conditional render */}
{isLoggedIn && <UserDashboard />}
{/* Multiple conditions */}
{isAdmin && user.permissions && <AdminControls />}
{/* Conditional with nested properties */}
{user?.subscription?.isActive && <PremiumContent />}
{/* Combining conditions */}
{(isAdmin || user.isModerator) && <ModTools />}
</div>
);
}
  1. Need multiple fallbacks? Combine them with parentheses:
JavaScript
// Multiple fallbacks with clear precedence
const theme = (userTheme ?? systemTheme) ?? 'light';
const name = (user?.name ?? savedName) ?? 'Anonymous';
// Real-world example: Complex configuration
const config = {
// Environment variables with fallbacks
port: (process.env.PORT ?? customPort) ?? 3000,
// User preferences with system defaults
theme: (userPrefs?.theme ?? systemTheme) ?? 'light',
// Feature flags with multiple layers
features: {
dark: (userFlags?.dark ?? betaFlags?.dark) ?? false,
experimental: (user?.beta && betaFeatures) ?? false
},
// API configuration with timeouts
api: {
timeout: (customTimeout ?? defaultTimeout) ?? 5000,
retries: (userRetries ?? systemRetries) ?? 3,
// Combining different operators for complex logic
endpoint: (isProd && PROD_API) || (isStaging && STAGING_API) || DEV_API
}
};

These operators are more than just syntax shortcuts - they’re tools for writing cleaner, more expressive code. Next time you’re about to write an if statement, consider if one of these operators might make your code more elegant.

My suggestion is to start with the nullish coalescing operator ?? for default values. It’s the newest addition to JavaScript, and it often leads to fewer surprises than the older OR operator ||

If you found this article helpful, you might enjoy my free newsletter. I share developer tips and insights to help you grow your skills and career.


More Articles You Might Enjoy

If you enjoyed this article, you might find these related pieces interesting as well. If you like what I have to say, please check out the sponsors who are supporting me. Much appreciated!

Javascript
4 min read

The Only Widely Recognized JavaScript Feature Ever Deprecated

The 'with' statement is the only feature ever deprecated in JavaScript

Aug 22, 2024
Read article
Javascript
3 min read

navigator.clipboard - The New Asynchronous Clipboard API in JavaScript

Copy and paste text, images, and files using the new navigator.clipboard API

Dec 7, 2024
Read article
Javascript
6 min read

Micro Frontends: The LEGO Approach to Web Development

Explore the concept of micro frontends in web development, understand their benefits, and learn when this architectural approach is most effective for building scalable applications.

Oct 2, 2024
Read article
Javascript
7 min read

What's New in Express.js v5.0

A detailed look at the key changes and improvements in Express v5.0 and how to migrate your app

Sep 16, 2024
Read article
Javascript
5 min read

Recursion Explained In Simple Terms

Understanding recursion through real examples - why functions call themselves and when to use them

Nov 22, 2024
Read article
Javascript
3 min read

JavaScript's &&= Operator: Understanding Logical AND Assignment

Use the &&= operator to safely update truthy values while preserving falsy states

Nov 5, 2024
Read article
Javascript
5 min read

Working with JavaScript's Scheduler API

Learn how to prioritize and control task execution in JavaScript using the new Scheduler API for better performance and user experience

Nov 26, 2024
Read article
Javascript
6 min read

AggregateError in JavaScript

AggregateError helps you handle multiple errors at once in JavaScript. This makes your code easier to manage and more reliable.

Sep 2, 2024
Read article
Javascript
4 min read

Understanding Bitwise Shifts in JavaScript: << and >>

A practical guide to left and right shift operators in JavaScript

Nov 12, 2024
Read article

Become a better engineer

Here are engineering resources I've personally vetted and use. They focus on skills you'll actually need to build and scale real projects - the kind of experience that gets you hired or promoted.

Many companies have a fixed annual stipend per engineer (e.g. $2,000) for use towards learning resources. If your company offers this stipend, you can forward them your invoices directly for reimbursement. By using my affiliate links, you support my work and get a discount at the same!


This article was originally published on https://www.trevorlasn.com/blog/javascript-logical-operators. It was written by a human and polished using grammar tools for clarity.