Тернарный оператор — это сокращённая форма записи условного выражения в JavaScript:
условие ? значение_если_true : значение_если_false
condition ? valueIfTrue : valueIfFalse
Элемент | Описание | Пример |
---|---|---|
Условие | Выражение, которое приводится к boolean | age >= 18 |
? | Оператор “если” | ? |
Значение true | Возвращается, если условие истинно | "Совершеннолетний" |
: | Разделитель “иначе” | : |
Значение false | Возвращается, если условие ложно | "Несовершеннолетний" |
// Общая форма
const result = condition ? valueIfTrue : valueIfFalse;
// Простой пример
const age = 20;
const status = age >= 18 ? "Взрослый" : "Ребёнок";
console.log(status); // "Взрослый"
// Эквивалент с if-else
let status2;
if (age >= 18) {
status2 = "Взрослый";
} else {
status2 = "Ребёнок";
}
// Проверка чётности числа
const number = 42;
const parity = number % 2 === 0 ? "чётное" : "нечётное";
console.log(`Число ${number} ${parity}`); // "Число 42 чётное"
// Определение знака числа
const value = -5;
const sign = value >= 0 ? "положительное" : "отрицательное";
console.log(`Число ${sign}`); // "Число отрицательное"
// Проверка на пустую строку
const input = "";
const message = input ? "Есть данные" : "Нет данных";
console.log(message); // "Нет данных"
// Установка значения по умолчанию
const userName = null;
const displayName = userName ? userName : "Гость";
console.log(`Привет, ${displayName}!`); // "Привет, Гость!"
// Выбор между двумя значениями
const theme = "dark";
const backgroundColor = theme === "dark" ? "#333" : "#fff";
const textColor = theme === "dark" ? "#fff" : "#333";
// Условное присваивание
const isLoggedIn = true;
const menuItems = isLoggedIn ? ["Профиль", "Настройки", "Выход"] : ["Вход", "Регистрация"];
// Выбор максимального значения
const a = 10, b = 15;
const max = a > b ? a : b;
console.log(`Максимум: ${max}`); // "Максимум: 15"
// Абсолютное значение
const num = -7;
const absolute = num >= 0 ? num : -num;
console.log(`|${num}| = ${absolute}`); // "|-7| = 7"
// Ограничение значения
const score = 150;
const limitedScore = score > 100 ? 100 : score;
console.log(`Ограниченный счёт: ${limitedScore}`); // "Ограниченный счёт: 100"
// Оценка по баллам
const score = 85;
const grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" :
score >= 60 ? "D" : "F";
console.log(`Оценка: ${grade}`); // "Оценка: B"
// Определение времени суток
const hour = 14;
const timeOfDay = hour < 6 ? "ночь" :
hour < 12 ? "утро" :
hour < 18 ? "день" : "вечер";
console.log(`Сейчас ${timeOfDay}`); // "Сейчас день"
// Категория возраста
const age = 25;
const category = age < 13 ? "ребёнок" :
age < 20 ? "подросток" :
age < 60 ? "взрослый" : "пожилой";
// Проверка доступа с несколькими условиями
const user = { role: "admin", isActive: true, hasPermission: true };
const access = user.role === "admin" ?
(user.isActive ?
(user.hasPermission ? "Полный доступ" : "Ограниченный доступ") :
"Аккаунт заблокирован") :
"Нет прав администратора";
// Более читаемая версия
const access2 = user.role === "admin" && user.isActive && user.hasPermission ?
"Полный доступ" :
user.role === "admin" && user.isActive ?
"Ограниченный доступ" :
user.role === "admin" ?
"Аккаунт заблокирован" :
"Нет прав администратора";
// Вместо сложных вложенных тернарных операторов
// лучше использовать функции или switch
function getAccessLevel(user) {
if (user.role !== "admin") {
return "Нет прав администратора";
}
if (!user.isActive) {
return "Аккаунт заблокирован";
}
return user.hasPermission ? "Полный доступ" : "Ограниченный доступ";
}
// Или с использованием объекта-карты
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";
}
// Простая функция с тернарным оператором
function isEven(number) {
return number % 2 === 0 ? true : false;
// Ещё лучше: return number % 2 === 0;
}
// Функция приветствия
function greet(name, timeOfDay) {
const greeting = timeOfDay === "morning" ? "Доброе утро" :
timeOfDay === "afternoon" ? "Добрый день" :
timeOfDay === "evening" ? "Добрый вечер" : "Привет";
return `${greeting}, ${name}!`;
}
// Функция валидации
function validateAge(age) {
return age >= 0 && age <= 120 ?
{ valid: true, message: "Возраст корректен" } :
{ valid: false, message: "Некорректный возраст" };
}
// Условный вызов функции
const isDebug = true;
const log = isDebug ? console.log : () => {};
log("Отладочное сообщение"); // Выведется только в режиме отладки
// Выбор обработчика
const userType = "premium";
const processPayment = userType === "premium" ?
processPremiumPayment :
processRegularPayment;
function processPremiumPayment(amount) {
return amount * 0.9; // 10% скидка
}
function processRegularPayment(amount) {
return amount;
}
// Условное выполнение
const shouldSendEmail = true;
shouldSendEmail ? sendWelcomeEmail() : logSkippedEmail();
// Условный рендеринг в React
function UserProfile({ user, isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<div>
<h1>Добро пожаловать, {user.name}!</h1>
<p>Email: {user.email}</p>
</div>
) : (
<div>
<h1>Пожалуйста, войдите в систему</h1>
<button>Войти</button>
</div>
)}
</div>
);
}
// Условные классы CSS
function Button({ isPrimary, isDisabled, children }) {
const className = `btn ${
isPrimary ? 'btn-primary' : 'btn-secondary'
} ${
isDisabled ? 'btn-disabled' : ''
}`;
return (
<button className={className} disabled={isDisabled}>
{children}
</button>
);
}
// Условный текст в шаблонах
const items = ["яблоко", "банан", "апельсин"];
const message = `У вас ${items.length} ${items.length === 1 ? 'товар' : 'товаров'} в корзине`;
// Условное форматирование
const price = 1234.56;
const currency = "RUB";
const formattedPrice = `${price.toFixed(2)} ${
currency === "RUB" ? "₽" :
currency === "USD" ? "$" :
currency === "EUR" ? "€" : currency
}`;
// Условные стили
const status = "error";
const statusMessage = `<span style="color: ${
status === "success" ? "green" :
status === "warning" ? "orange" :
status === "error" ? "red" : "black"
}">${status}</span>`;
Критерий | Тернарный оператор | if-else |
---|---|---|
Краткость | ✅ Очень краткий | ❌ Более многословный |
Читаемость | ✅ Для простых условий | ✅ Для сложных условий |
Возврат значения | ✅ Выражение | ❌ Требует переменную |
Вложенность | ❌ Может быть сложной | ✅ Более понятная |
Производительность | ✅ Немного быстрее | ✅ Практически равная |
Отладка | ❌ Сложнее | ✅ Проще |
// ✅ ХОРОШО: Простые условия
const status = isOnline ? "В сети" : "Не в сети";
const color = isDark ? "white" : "black";
const price = hasDiscount ? originalPrice * 0.8 : originalPrice;
// ✅ ХОРОШО: Присваивание значений
const greeting = hour < 12 ? "Доброе утро" : "Добрый день";
const icon = isLoading ? "spinner" : "check";
// ✅ ХОРОШО: Возврат из функции
function getDiscount(userType) {
return userType === "premium" ? 0.2 : 0.1;
}
// ✅ ХОРОШО: В выражениях
console.log(`Результат: ${isSuccess ? "Успех" : "Ошибка"}`);
array.filter(item => item.active ? item : null);
// ✅ ХОРОШО: Сложная логика
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");
}
// ✅ ХОРОШО: Множественные действия
if (isFormValid) {
submitForm();
showSuccessMessage();
redirectToNextPage();
} else {
highlightErrors();
focusFirstError();
trackValidationError();
}
// ✅ ХОРОШО: Сложные вложенные условия
if (weather.temperature > 25) {
if (weather.humidity > 70) {
recommendation = "Жарко и влажно, оставайтесь дома";
} else {
recommendation = "Отличная погода для прогулки";
}
} else if (weather.temperature < 0) {
recommendation = "Холодно, одевайтесь теплее";
} else {
recommendation = "Приятная погода";
}
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);
5
(поскольку 5 не больше 10, возвращается b / 2 = 10 / 2 = 5)
"false"
(0 приводится к false)
"empty"
(пустая строка приводится к false)
let message;
if (user.isVip) {
message = "Добро пожаловать, VIP пользователь!";
} else {
message = "Добро пожаловать!";
}
let discount;
if (order.total > 1000) {
discount = 0.1;
} else {
discount = 0;
}
const message = user.isVip ?
"Добро пожаловать, VIP пользователь!" :
"Добро пожаловать!";
const discount = order.total > 1000 ? 0.1 : 0;
// Создайте функцию getSeason, которая принимает номер месяца (1-12)
// и возвращает название сезона
function getSeason(month) {
// Ваш код здесь
}
console.log(getSeason(3)); // "весна"
console.log(getSeason(7)); // "лето"
console.log(getSeason(10)); // "осень"
console.log(getSeason(1)); // "зима"
function getSeason(month) {
return month >= 3 && month <= 5 ? "весна" :
month >= 6 && month <= 8 ? "лето" :
month >= 9 && month <= 11 ? "осень" : "зима";
}
// Альтернативный вариант
function getSeason(month) {
return month === 12 || month <= 2 ? "зима" :
month <= 5 ? "весна" :
month <= 8 ? "лето" : "осень";
}
// Создайте функцию validateInput, которая проверяет:
// - email содержит @
// - password длиннее 6 символов
// - age больше 0 и меньше 120
// Возвращает объект с результатом валидации
function validateInput(email, password, age) {
// Ваш код здесь
}
const result = validateInput("test@mail.com", "123456789", 25);
console.log(result); // { valid: true, errors: [] }
function validateInput(email, password, age) {
const errors = [];
!email.includes("@") ? errors.push("Некорректный email") : null;
password.length <= 6 ? errors.push("Пароль слишком короткий") : null;
age <= 0 || age >= 120 ? errors.push("Некорректный возраст") : null;
return {
valid: errors.length === 0,
errors: errors
};
}
// Более читаемая версия
function validateInput(email, password, age) {
const isEmailValid = email.includes("@");
const isPasswordValid = password.length > 6;
const isAgeValid = age > 0 && age < 120;
const errors = [
...(!isEmailValid ? ["Некорректный email"] : []),
...(!isPasswordValid ? ["Пароль слишком короткий"] : []),
...(!isAgeValid ? ["Некорректный возраст"] : [])
];
return {
valid: errors.length === 0,
errors
};
}
// Какой вариант быстрее и почему?
// Вариант A
function getStatusA(user) {
if (user.isActive) {
return "Активен";
} else {
return "Неактивен";
}
}
// Вариант B
function getStatusB(user) {
return user.isActive ? "Активен" : "Неактивен";
}
// Вариант C
const getStatusC = (user) => user.isActive ? "Активен" : "Неактивен";
Все варианты имеют практически одинаковую производительность. Современные JavaScript движки оптимизируют код на уровне байт-кода.
Вариант B и C предпочтительнее по следующим причинам:
Вариант A лучше для сложной логики с множественными действиями.
// Условная деструктуризация
const user = { name: "Иван", email: "ivan@mail.com" };
const { name, email = "Не указан" } = user.email ? user : {};
// Условное присваивание с деструктуризацией
const config = isDevelopment ?
{ apiUrl: "http://localhost:3000", debug: true } :
{ apiUrl: "https://api.production.com", debug: false };
const { apiUrl, debug } = config;
// Условный spread
const baseStyles = { padding: "10px", margin: "5px" };
const buttonStyles = {
...baseStyles,
...(isPrimary ? { backgroundColor: "blue", color: "white" } : {}),
...(isLarge ? { fontSize: "18px", padding: "15px" } : {})
};
// Тернарный оператор в методах массивов
const numbers = [1, 2, 3, 4, 5];
// Условная фильтрация
const filtered = numbers.filter(n => showEven ? n % 2 === 0 : n % 2 !== 0);
// Условное преобразование
const transformed = numbers.map(n =>
n > 3 ? n * 2 : n
);
// Условная сортировка
const sorted = numbers.sort((a, b) =>
ascending ? a - b : b - a
);
// Условное сведение
const result = numbers.reduce((acc, n) =>
n % 2 === 0 ? acc + n : acc, 0
);
// Функция высшего порядка с тернарным оператором
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(-1)); // { valid: false, error: "Validation failed" }
// Условное каррирование
const mathOperation = (operation) => (a) => (b) =>
operation === "add" ? a + b :
operation === "subtract" ? a - b :
operation === "multiply" ? a * b :
operation === "divide" ? (b !== 0 ? a / b : "Division by zero") :
"Unknown operation";
const add = mathOperation("add");
const multiply = mathOperation("multiply");
console.log(add(5)(3)); // 8
console.log(multiply(4)(7)); // 28
// Условная мемоизация
function createMemoizedFunction(fn, shouldMemoize = true) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
return shouldMemoize && cache.has(key) ?
cache.get(key) :
(() => {
const result = fn.apply(this, args);
shouldMemoize ? cache.set(key, result) : null;
return result;
})();
};
}
// Условное кеширование API запросов
const apiCall = createMemoizedFunction(
async (url) => {
const response = await fetch(url);
return response.json();
},
process.env.NODE_ENV === "production" // Кешируем только в продакшене
);
// ❌ ПЛОХО: Слишком сложно для понимания
const result = a > b ?
(c > d ?
(e > f ? "case1" : "case2") :
(g > h ? "case3" : "case4")) :
(i > j ?
(k > l ? "case5" : "case6") :
"case7");
// ✅ ХОРОШО: Используйте функции или switch
function getComplexResult(a, b, c, d, e, f, g, h, i, j, k, l) {
if (a <= b) {
return i > j ? (k > l ? "case5" : "case6") : "case7";
}
if (c > d) {
return e > f ? "case1" : "case2";
}
return g > h ? "case3" : "case4";
}
// ❌ ПЛОХО: Побочные эффекты в условии
let counter = 0;
const result = ++counter > 5 ? "high" : "low";
// ❌ ПЛОХО: Мутация в тернарном операторе
const processArray = (arr) =>
arr.length > 0 ? arr.push("new item") : arr;
// ✅ ХОРОШО: Чистые функции
let counter = 0;
counter++;
const result = counter > 5 ? "high" : "low";
// ✅ ХОРОШО: Без мутаций
const processArray = (arr) =>
arr.length > 0 ? [...arr, "new item"] : arr;
// ❌ ПЛОХО: Неясная приоритетность
const result = a + b > c ? d * e : f / g + h;
// ✅ ХОРОШО: Явные скобки
const result = (a + b) > c ? (d * e) : ((f / g) + h);
// ❌ ПЛОХО: Смешивание с логическими операторами
const value = isTrue && condition ? "yes" : "no" || "maybe";
// ✅ ХОРОШО: Явная группировка
const value = (isTrue && condition) ? "yes" : ("no" || "maybe");
// ❌ ПЛОХО: Неожиданное приведение типов
const result = someValue ? "string" : 0; // Может вернуть разные типы
// ✅ ХОРОШО: Согласованные типы
const result = someValue ? "has value" : "no value";
const numericResult = someValue ? 1 : 0;
// ❌ ПЛОХО: Проблемы с null/undefined
const name = user.name ? user.name : "Unknown"; // Не сработает для пустой строки
// ✅ ХОРОШО: Правильная проверка
const name = user.name != null && user.name !== "" ? user.name : "Unknown";
// Или с nullish coalescing (ES2020)
const name = user.name ?? "Unknown";
// Старый способ с тернарным оператором
const value1 = someValue !== null && someValue !== undefined ? someValue : "default";
// Новый способ с nullish coalescing
const value2 = someValue ?? "default";
// Разница в поведении
const test1 = "" ? "not empty" : "empty"; // "empty"
const test2 = "" ?? "empty"; // "" (пустая строка не null/undefined)
const test3 = 0 ? "not zero" : "zero"; // "zero"
const test4 = 0 ?? "zero"; // 0 (ноль не null/undefined)
// Старый способ с тернарным оператором
const street = user && user.address && user.address.street ?
user.address.street :
"Адрес не указан";
// Новый способ с optional chaining
const street = user?.address?.street ?? "Адрес не указан";
// Условный вызов методов
const result = user?.getName ? user.getName() : "Имя не доступно";
// Или
const result = user?.getName?.() ?? "Имя не доступно";
// ES2021: Логическое присваивание
let config = {};
// Старый способ
config.theme = config.theme ? config.theme : "light";
// С тернарным оператором
config.theme = config.theme ? config.theme : "light";
// Новый способ
config.theme ||= "light";
config.debug ??= false;
config.features &&= config.features.filter(f => f.enabled);
// ✅ ХОРОШО: Простые условия
const status = isOnline ? "online" : "offline";
const price = hasDiscount ? originalPrice * 0.8 : originalPrice;
// ✅ ХОРОШО: Разбивка на строки для сложных случаев
const message = user.isVip ?
`Добро пожаловать, ${user.name}! У вас VIP статус.` :
`Добро пожаловать, ${user.name}!`;
// ✅ ХОРОШО: Вынос условий в переменные
const isEligibleForDiscount = user.isVip || user.purchaseCount > 10;
const finalPrice = isEligibleForDiscount ? price * 0.9 : price;
// ✅ ХОРОШО: Одинаковые типы
const result = isSuccess ? "Успех" : "Ошибка";
const count = hasItems ? items.length : 0;
const handler = isEnabled ? enabledHandler : disabledHandler;
// ❌ ИЗБЕГАЙТЕ: Разные типы
const mixed = isSuccess ? "Success" : false; // string | boolean
const confusing = hasData ? data : null; // object | null
// ✅ ХОРОШО: Дешёвые операции в условии
const result = isSimpleFlag ? expensiveOperation() : defaultValue;
// ❌ ИЗБЕГАЙТЕ: Дорогие операции в условии
const bad = expensiveCheck() ? value1 : value2;
// ✅ ЛУЧШЕ: Кеширование результата
const isExpensive = expensiveCheck();
const good = isExpensive ? value1 : value2;
// ✅ ХОРОШО: Легко тестировать
function getDiscountedPrice(price, userType) {
return userType === "premium" ? price * 0.8 : price;
}
// ✅ ХОРОШО: Чистые функции
const formatCurrency = (amount, currency) =>
currency === "USD" ? `$${amount}` : `${amount} ${currency}`;
// ❌ ИЗБЕГАЙТЕ: Зависимость от внешнего состояния
const formatPrice = (amount) =>
globalCurrency === "USD" ? `$${amount}` : `${amount} ${globalCurrency}`;
Тернарный оператор — это мощный инструмент для написания краткого и выразительного кода. Важно помнить:
✅ Используйте для простых условий — одно условие, два возможных значения
✅ Поддерживайте читаемость — если код сложно понять, используйте if-else
✅ Следите за типами — возвращаемые значения должны быть согласованы
✅ Избегайте побочных эффектов — тернарный оператор для выражений, не действий
✅ Комбинируйте с современными операторами — ??, ?., ||=, &&=, ??=
В современной разработке предпочитайте:
Освойте тернарный оператор, чтобы писать более элегантный и функциональный JavaScript код! 🚀