What is the ternary operator and how does it work in JavaScript?

👨‍💻 Frontend Developer 🟠 May come up 🎚️ Easy
#JavaScript #JS Basics #Conditional

Quick Answer

The ternary operator — is a shortened form of writing conditional expressions in JavaScript:

condition ? value_if_true : value_if_false
  • Syntax: condition ? valueIfTrue : valueIfFalse
  • Returns: one of two values depending on the condition
  • Alternative: if-else constructs for simple cases
  • Advantages: brevity, readability, ability to use in expressions

Syntax and Basics

ElementDescriptionExample
ConditionExpression that is converted to booleanage >= 18
?”If” operator?
True valueReturned if condition is true"Adult"
:“Else” separator:
False valueReturned if condition is false"Minor"

Basic Syntax

// General form
const result = condition ? valueIfTrue : valueIfFalse;
 
// Simple example
const age = 20;
const status = age >= 18 ? "Adult" : "Child";
console.log(status); // "Adult"
 
// Equivalent with if-else
let status2;
if (age >= 18) {
  status2 = "Adult";
} else {
  status2 = "Child";
}

1. Basic Usage Examples

Simple Conditions

// Check if number is even
const number = 42;
const parity = number % 2 === 0 ? "even" : "odd";
console.log(`Number ${number} is ${parity}`); // "Number 42 is even"
 
// Determine number sign
const value = -5;
const sign = value >= 0 ? "positive" : "negative";
console.log(`Number is ${sign}`); // "Number is negative"
 
// Check for empty string
const input = "";
const message = input ? "Has data" : "No data";
console.log(message); // "No data"

Working with Variables

// Set default value
const userName = null;
const displayName = userName ? userName : "Guest";
console.log(`Hello, ${displayName}!`); // "Hello, Guest!"
 
// Choose between two values
const theme = "dark";
const backgroundColor = theme === "dark" ? "#333" : "#fff";
const textColor = theme === "dark" ? "#fff" : "#333";
 
// Conditional assignment
const isLoggedIn = true;
const menuItems = isLoggedIn ? ["Profile", "Settings", "Logout"] : ["Login", "Register"];

Mathematical Operations

// Choose maximum value
const a = 10, b = 15;
const max = a > b ? a : b;
console.log(`Maximum: ${max}`); // "Maximum: 15"
 
// Absolute value
const num = -7;
const absolute = num >= 0 ? num : -num;
console.log(`|${num}| = ${absolute}`); // "|-7| = 7"
 
// Limit value
const score = 150;
const limitedScore = score > 100 ? 100 : score;
console.log(`Limited score: ${limitedScore}`); // "Limited score: 100"

2. Nested Ternary Operators

Multiple Conditions

// Grade by score
const score = 85;
const grade = score >= 90 ? "A" : 
              score >= 80 ? "B" : 
              score >= 70 ? "C" : 
              score >= 60 ? "D" : "F";
console.log(`Grade: ${grade}`); // "Grade: B"
 
// Determine time of day
const hour = 14;
const timeOfDay = hour < 6 ? "night" :
                  hour < 12 ? "morning" :
                  hour < 18 ? "afternoon" : "evening";
console.log(`It's ${timeOfDay} now`); // "It's afternoon now"
 
// Age category
const age = 25;
const category = age < 13 ? "child" :
                 age < 20 ? "teenager" :
                 age < 60 ? "adult" : "elderly";

Complex Conditions

// Access check with multiple conditions
const user = { role: "admin", isActive: true, hasPermission: true };
const access = user.role === "admin" ? 
               (user.isActive ? 
                (user.hasPermission ? "Full access" : "Limited access") : 
                "Account blocked") : 
               "No admin rights";
 
// More readable version
const access2 = user.role === "admin" && user.isActive && user.hasPermission ? 
                "Full access" : 
                user.role === "admin" && user.isActive ? 
                "Limited access" : 
                user.role === "admin" ? 
                "Account blocked" : 
                "No admin rights";

Alternatives for Complex Cases

// Instead of complex nested ternary operators
// it's better to use functions or switch
 
function getAccessLevel(user) {
  if (user.role !== "admin") {
    return "No admin rights";
  }
  
  if (!user.isActive) {
    return "Account blocked";
  }
  
  return user.hasPermission ? "Full access" : "Limited access";
}
 
// Or using object map
const gradeMap = {
  90: "A", 80: "B", 70: "C", 60: "D"
};
 
function getGrade(score) {
  const threshold = Object.keys(gradeMap)
    .map(Number)
    .find(threshold => score >= threshold);
  return gradeMap[threshold] || "F";
}

3. Ternary Operator in Functions

Return Values

// Simple function with ternary operator
function isEven(number) {
  return number % 2 === 0 ? true : false;
  // Even better: return number % 2 === 0;
}
 
// Greeting function
function greet(name, timeOfDay) {
  const greeting = timeOfDay === "morning" ? "Good morning" :
                   timeOfDay === "afternoon" ? "Good afternoon" :
                   timeOfDay === "evening" ? "Good evening" : "Hello";
  return `${greeting}, ${name}!`;
}
 
// Validation function
function validateAge(age) {
  return age >= 0 && age <= 120 ? 
         { valid: true, message: "Age is correct" } :
         { valid: false, message: "Invalid age" };
}

Conditional Function Calls

// Conditional function call
const isDebug = true;
const log = isDebug ? console.log : () => {};
log("Debug message"); // Will output only in debug mode
 
// Handler selection
const userType = "premium";
const processPayment = userType === "premium" ? 
                       processPremiumPayment : 
                       processRegularPayment;
 
function processPremiumPayment(amount) {
  return amount * 0.9; // 10% discount
}
 
function processRegularPayment(amount) {
  return amount;
}
 
// Conditional execution
const shouldSendEmail = true;
shouldSendEmail ? sendWelcomeEmail() : logSkippedEmail();

4. Ternary Operator in JSX and Templates

React Components

// Conditional rendering in React
function UserProfile({ user, isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <div>
          <h1>Welcome, {user.name}!</h1>
          <p>Email: {user.email}</p>
        </div>
      ) : (
        <div>
          <h1>Please log in</h1>
          <button>Login</button>
        </div>
      )}
    </div>
  );
}
 
// Conditional CSS classes
function Button({ isPrimary, isDisabled, children }) {
  const className = `btn ${
    isPrimary ? 'btn-primary' : 'btn-secondary'
  } ${
    isDisabled ? 'btn-disabled' : ''
  }`;
  
  return (
    <button className={className} disabled={isDisabled}>
      {children}
    </button>
  );
}

Template Strings

// Conditional text in templates
const items = ["apple", "banana", "orange"];
const message = `You have ${items.length} ${items.length === 1 ? 'item' : 'items'} in cart`;
 
// Conditional formatting
const price = 1234.56;
const currency = "USD";
const formattedPrice = `${price.toFixed(2)} ${
  currency === "RUB" ? "₽" : 
  currency === "USD" ? "$" : 
  currency === "EUR" ? "€" : currency
}`;
 
// Conditional styles
const status = "error";
const statusMessage = `<span style="color: ${
  status === "success" ? "green" :
  status === "warning" ? "orange" :
  status === "error" ? "red" : "black"
}">${status}</span>`;

5. Comparison with if-else

CriteriaTernary Operatorif-else
Brevity✅ Very concise❌ More verbose
Readability✅ For simple conditions✅ For complex conditions
Return value✅ Expression❌ Requires variable
Nesting❌ Can be complex✅ More understandable
Performance✅ Slightly faster✅ Practically equal
Debugging❌ Harder✅ Easier

When to Use Ternary Operator

// ✅ GOOD: Simple conditions
const status = isOnline ? "Online" : "Offline";
const color = isDark ? "white" : "black";
const price = hasDiscount ? originalPrice * 0.8 : originalPrice;
 
// ✅ GOOD: Value assignment
const greeting = hour < 12 ? "Good morning" : "Good afternoon";
const icon = isLoading ? "spinner" : "check";
 
// ✅ GOOD: Function return
function getDiscount(userType) {
  return userType === "premium" ? 0.2 : 0.1;
}
 
// ✅ GOOD: In expressions
console.log(`Result: ${isSuccess ? "Success" : "Error"}`);
array.filter(item => item.active ? item : null);

When to Use if-else

// ✅ GOOD: Complex logic
if (user.role === "admin" && user.permissions.includes("write")) {
  allowEdit = true;
  logAction("edit_allowed", user.id);
  sendNotification("Admin edit access granted");
} else {
  allowEdit = false;
  logAction("edit_denied", user.id);
  showErrorMessage("Insufficient permissions");
}
 
// ✅ GOOD: Multiple actions
if (isFormValid) {
  submitForm();
  showSuccessMessage();
  redirectToNextPage();
} else {
  highlightErrors();
  focusFirstError();
  trackValidationError();
}
 
// ✅ GOOD: Complex nested conditions
if (weather.temperature > 25) {
  if (weather.humidity > 70) {
    recommendation = "Hot and humid, stay home";
  } else {
    recommendation = "Great weather for a walk";
  }
} else if (weather.temperature < 0) {
  recommendation = "Cold, dress warmly";
} else {
  recommendation = "Pleasant weather";
}

Practical Tasks

Task 1: What will the console output?

const a = 5;
const b = 10;
const result = a > b ? a * 2 : b / 2;
console.log(result);
 
const x = 0;
const y = x ? "true" : "false";
console.log(y);
 
const str = "";
const output = str ? str.toUpperCase() : "empty";
console.log(output);
Answer

5 (since 5 is not greater than 10, returns b / 2 = 10 / 2 = 5) "false" (0 is converted to false) "empty" (empty string is converted to false)

Task 2: Simplify the code

let message;
if (user.isVip) {
  message = "Welcome, VIP user!";
} else {
  message = "Welcome!";
}
 
let discount;
if (order.total > 1000) {
  discount = 0.1;
} else {
  discount = 0;
}
Answer
const message = user.isVip ? 
  "Welcome, VIP user!" : 
  "Welcome!";
 
const discount = order.total > 1000 ? 0.1 : 0;

Task 3: Create a season determination function

// Create getSeason function that takes month number (1-12)
// and returns season name
function getSeason(month) {
  // Your code here
}
 
console.log(getSeason(3)); // "spring"
console.log(getSeason(7)); // "summer"
console.log(getSeason(10)); // "autumn"
console.log(getSeason(1)); // "winter"
Answer
function getSeason(month) {
  return month >= 3 && month <= 5 ? "spring" :
         month >= 6 && month <= 8 ? "summer" :
         month >= 9 && month <= 11 ? "autumn" : "winter";
}
 
// Alternative version
function getSeason(month) {
  return month === 12 || month <= 2 ? "winter" :
         month <= 5 ? "spring" :
         month <= 8 ? "summer" : "autumn";
}

Task 4: Form validation

// Create validateInput function that checks:
// - email contains @
// - password is longer than 6 characters
// - age is greater than 0 and less than 120
// Returns object with validation result
 
function validateInput(email, password, age) {
  // Your code here
}
 
const result = validateInput("test@mail.com", "123456789", 25);
console.log(result); // { valid: true, errors: [] }
Answer
function validateInput(email, password, age) {
  const errors = [];
  
  !email.includes("@") ? errors.push("Invalid email") : null;
  password.length <= 6 ? errors.push("Password too short") : null;
  age <= 0 || age >= 120 ? errors.push("Invalid age") : null;
  
  return {
    valid: errors.length === 0,
    errors: errors
  };
}
 
// More readable version
function validateInput(email, password, age) {
  const isEmailValid = email.includes("@");
  const isPasswordValid = password.length > 6;
  const isAgeValid = age > 0 && age < 120;
  
  const errors = [
    ...(!isEmailValid ? ["Invalid email"] : []),
    ...(!isPasswordValid ? ["Password too short"] : []),
    ...(!isAgeValid ? ["Invalid age"] : [])
  ];
  
  return {
    valid: errors.length === 0,
    errors
  };
}

Task 5: Performance optimization

// Which variant is faster and why?
 
// Variant A
function getStatusA(user) {
  if (user.isActive) {
    return "Active";
  } else {
    return "Inactive";
  }
}
 
// Variant B
function getStatusB(user) {
  return user.isActive ? "Active" : "Inactive";
}
 
// Variant C
const getStatusC = (user) => user.isActive ? "Active" : "Inactive";
Answer

All variants have practically the same performance. Modern JavaScript engines optimize code at the bytecode level.

Variants B and C are preferable for the following reasons:

  • Less code
  • More functional style
  • Easier to read for simple conditions
  • Less room for errors

Variant A is better for complex logic with multiple actions.


Advanced Techniques

Ternary Operator with Destructuring

// Conditional destructuring
const user = { name: "John", email: "john@mail.com" };
const { name, email = "Not specified" } = user.email ? user : {};
 
// Conditional assignment with destructuring
const config = isDevelopment ? 
  { apiUrl: "http://localhost:3000", debug: true } :
  { apiUrl: "https://api.production.com", debug: false };
 
const { apiUrl, debug } = config;
 
// Conditional spread
const baseStyles = { padding: "10px", margin: "5px" };
const buttonStyles = {
  ...baseStyles,
  ...(isPrimary ? { backgroundColor: "blue", color: "white" } : {}),
  ...(isLarge ? { fontSize: "18px", padding: "15px" } : {})
};

Functional Programming

// Ternary operator in array methods
const numbers = [1, 2, 3, 4, 5];
 
// Conditional filtering
const filtered = numbers.filter(n => showEven ? n % 2 === 0 : n % 2 !== 0);
 
// Conditional transformation
const transformed = numbers.map(n => 
  n > 3 ? n * 2 : n
);
 
// Conditional sorting
const sorted = numbers.sort((a, b) => 
  ascending ? a - b : b - a
);
 
// Conditional reduction
const result = numbers.reduce((acc, n) => 
  n % 2 === 0 ? acc + n : acc, 0
);

Currying and Partial Application

// Higher-order function with ternary operator
const createValidator = (condition) => (value) => 
  condition(value) ? { valid: true } : { valid: false, error: "Validation failed" };
 
const isPositive = (n) => n > 0;
const validatePositive = createValidator(isPositive);
 
console.log(validatePositive(5)); // { valid: true }
console.log(validatePositive(-3)); // { valid: false, error: "Validation failed" }
 
// Conditional function composition
const transform = (shouldDouble, shouldSquare) => (value) => 
  shouldDouble ? 
    (shouldSquare ? value * value * 2 : value * 2) :
    (shouldSquare ? value * value : value);
 
const doubleAndSquare = transform(true, true);
console.log(doubleAndSquare(3)); // 18 (3 * 3 * 2)

Memoization with Ternary Operator

// Simple memoization
const memoize = (fn) => {
  const cache = new Map();
  return (arg) => {
    return cache.has(arg) ? 
           cache.get(arg) : 
           (() => {
             const result = fn(arg);
             cache.set(arg, result);
             return result;
           })();
  };
};
 
// Conditional caching
const expensiveFunction = memoize((n) => {
  console.log(`Computing for ${n}`);
  return n * n;
});
 
console.log(expensiveFunction(5)); // Computing for 5, returns 25
console.log(expensiveFunction(5)); // returns 25 (from cache)

Common Mistakes

1. Overuse of Nested Ternary Operators

// ❌ BAD: Too complex
const result = a > b ? 
               (c > d ? 
                (e > f ? "case1" : "case2") : 
                (g > h ? "case3" : "case4")) : 
               (i > j ? "case5" : "case6");
 
// ✅ GOOD: Use function or if-else
function getResult() {
  if (a > b) {
    if (c > d) {
      return e > f ? "case1" : "case2";
    } else {
      return g > h ? "case3" : "case4";
    }
  } else {
    return i > j ? "case5" : "case6";
  }
}

2. Incorrect Type Coercion

// ❌ BAD: Unexpected behavior
const value = 0;
const result = value ? "has value" : "no value";
console.log(result); // "no value" (0 is falsy)
 
// ✅ GOOD: Explicit check
const result2 = value !== undefined && value !== null ? "has value" : "no value";
 
// ✅ GOOD: For numbers
const result3 = typeof value === "number" ? "has value" : "no value";

3. Side Effects in Ternary Operator

// ❌ BAD: Side effects
let counter = 0;
const result = condition ? counter++ : counter--;
 
// ✅ GOOD: Pure expressions
const result2 = condition ? counter + 1 : counter - 1;
if (condition) {
  counter++;
} else {
  counter--;
}

4. Ignoring Readability

// ❌ BAD: Hard to read
const msg = usr.isVip?usr.name+" (VIP)":usr.name||"Guest";
 
// ✅ GOOD: Readable formatting
const msg = usr.isVip ? 
            `${usr.name} (VIP)` : 
            usr.name || "Guest";
 
// ✅ EVEN BETTER: Clear variable names
const userName = usr.name || "Guest";
const vipSuffix = usr.isVip ? " (VIP)" : "";
const message = `${userName}${vipSuffix}`;

Modern JavaScript Features

Nullish Coalescing Operator (??)

// Traditional ternary for null/undefined check
const value1 = data !== null && data !== undefined ? data : "default";
 
// Modern nullish coalescing
const value2 = data ?? "default";
 
// Combination with ternary
const result = data ?? (isSpecialCase ? "special" : "default");
 
// Conditional nullish coalescing
const config = {
  timeout: userTimeout ?? (isDevelopment ? 1000 : 5000),
  retries: userRetries ?? (isProduction ? 3 : 1)
};

Optional Chaining (?.)

// Traditional ternary for safe property access
const city = user && user.address && user.address.city ? 
             user.address.city : 
             "Unknown";
 
// Modern optional chaining with ternary
const city2 = user?.address?.city ?? "Unknown";
 
// Conditional method calls
const result = user?.isAdmin?.() ? 
               "Admin access" : 
               "Regular access";
 
// Array access with ternary
const firstItem = items?.[0] ? 
                  items[0] : 
                  "No items";

Logical Assignment Operators

// Traditional ternary assignment
config.timeout = config.timeout ? config.timeout : 5000;
 
// Modern logical assignment
config.timeout ||= 5000;
 
// Nullish assignment with ternary
config.retries ??= isDevelopment ? 1 : 3;
 
// Conditional logical assignment
user.preferences &&= user.isActive ? 
                     user.preferences : 
                     defaultPreferences;

Template Literals with Ternary

// Complex template with ternary operators
const notification = `
  <div class="notification ${
    type === "error" ? "error" : 
    type === "warning" ? "warning" : 
    "info"
  }">
    <h3>${title}</h3>
    <p>${message}</p>
    ${showButton ? 
      `<button onclick="${action}">${buttonText}</button>` : 
      ""
    }
  </div>
`;
 
// Conditional styling
const styles = `
  color: ${isDark ? "white" : "black"};
  background: ${isDark ? "#333" : "#fff"};
  font-size: ${isLarge ? "18px" : "14px"};
  padding: ${isCompact ? "5px" : "10px"};
`;

Performance Considerations

Optimization Tips

// ✅ GOOD: Short-circuit evaluation
const result = expensiveCheck() ? 
               expensiveOperation() : 
               cheapDefault;
 
// ✅ GOOD: Avoid repeated calculations
const threshold = calculateThreshold();
const category = value > threshold ? "high" : "low";
 
// ❌ BAD: Repeated expensive calls
const category2 = value > calculateThreshold() ? 
                  "high" : 
                  "low";
 
// ✅ GOOD: Cache complex conditions
const isEligible = user.age >= 18 && user.hasAccount && user.isVerified;
const access = isEligible ? "granted" : "denied";

Memory Efficiency

// ✅ GOOD: Reuse objects
const successResponse = { status: "success", data: null };
const errorResponse = { status: "error", message: null };
 
function createResponse(isSuccess, payload) {
  return isSuccess ? 
         { ...successResponse, data: payload } :
         { ...errorResponse, message: payload };
}
 
// ✅ GOOD: Conditional object creation
const config = {
  ...baseConfig,
  ...(isDevelopment ? devConfig : prodConfig),
  ...(hasFeatureFlag ? experimentalConfig : {})
};

Conclusion

The ternary operator is a powerful tool for writing concise conditional expressions in JavaScript. It’s best suited for simple conditions and value assignments, while complex logic should use traditional if-else statements for better readability.

Key takeaways:

  • Use for simple conditions and value assignments
  • Avoid deep nesting
  • Prioritize readability over brevity
  • Combine with modern JavaScript features
  • Consider performance implications
  • Use appropriate formatting for complex expressions

Mastering the ternary operator will make your JavaScript code more concise and expressive while maintaining readability and performance.