Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Оператор ? — различные применения
Оператор ? в JavaScript и TypeScript имеет несколько применений в зависимости от контекста. Я использую все из них в production.
1. Nullish Coalescing Operator (??)
Возвращает правый операнд если левый null или undefined:
const name = userInput ?? 'Anonymous';
// Эквивалент с ||, но лучше
const name = userInput || 'Anonymous'; // Плохо для 0, '', false
// Разница:
const count = 0;
console.log(count || 10); // 10 (неправильно!)
console.log(count ?? 10); // 0 (правильно!)
const text = '';
console.log(text || 'default'); // 'default' (неправильно!)
console.log(text ?? 'default'); // '' (правильно!)
Практическое использование:
// Параметры с дефолтными значениями
function createUser(name, email) {
const finalName = name ?? 'Guest';
const finalEmail = email ?? 'no-email@example.com';
return { name: finalName, email: finalEmail };
}
creatеUser(null, undefined); // { name: 'Guest', email: 'no-email@example.com' }
creatеUser(0, ''); // { name: 0, email: '' }
2. Optional Chaining Operator (?.)
Безопасный доступ к свойствам (не выбросит ошибку если null/undefined):
// Плохо — может выбросить ошибку
const city = user.profile.address.city; // TypeError if user is null
// Хорошо — безопасно
const city = user?.profile?.address?.city; // undefined если любой null
Три варианта optional chaining:
// 1. Доступ к свойству
const name = user?.name;
const bio = user?.profile?.bio;
// 2. Вызов метода
const message = user?.getMessage?.();
const count = array?.length;
// 3. Доступ к элементу массива
const first = array?.[0];
const value = obj?.[dynamicKey];
Практические примеры:
// API ответ может быть неполным
const response = await fetch('/api/users/1');
const user = await response.json();
// Без optional chaining — потенциальная ошибка
const city = user.profile.address.city; // Может быть null!
// С optional chaining — безопасно
const city = user?.profile?.address?.city; // undefined
В React компонентах:
function UserProfile({ user }) {
return (
<div>
{/* Без optional chaining — ошибка */}
<p>{user.name}</p> {/* Может быть null! */}
{/* С optional chaining — безопасно */}
<p>{user?.name}</p>
<img src={user?.profile?.avatar} />
<button onClick={user?.getMessage?.()}>
Send Message
</button>
</div>
);
}
3. Conditional (Ternary) Operator
Условный оператор — condition ? true : false:
const status = isLoggedIn ? 'Welcome' : 'Please login';
// Вложенный
const userRole =
isAdmin ? 'Admin'
: isEditor ? 'Editor'
: 'User';
В React (очень частое использование):
function Dashboard() {
const isLoading = true;
const hasError = false;
const data = null;
return (
<div>
{isLoading ? (
<Spinner />
) : hasError ? (
<Error />
) : data ? (
<Content data={data} />
) : (
<Empty />
)}
</div>
);
}
4. Оператор в TypeScript типах
Optional свойства:
interface User {
id: string; // Обязательное
name: string; // Обязательное
email?: string; // Опциональное (может быть undefined)
phone?: string; // Опциональное
}
const user: User = { id: '1', name: 'John' }; // OK
Union типы с null:
type Username = string | null;
type Email = string | undefined;
type Value = string | number | null | undefined;
// С strict mode нужно явно обрабатывать
const name: Username = getNullableName();
if (name !== null) {
console.log(name.toUpperCase()); // Type-safe
}
5. Комбинирование операторов
Часто используемый паттерн:
// Получить значение или дефолт, безопасно
const city = user?.profile?.address?.city ?? 'Unknown';
// Вызвать функцию если она существует, иначе дефолт
const result = user?.getMessage?.() ?? 'No message';
// Условное отображение в React
const displayName = user?.name && user.name.length > 0
? user.name
: 'Anonymous';
Практический пример (API обработка):
function handleUserResponse(response) {
// Безопасно обработать неполный ответ
const user = {
id: response?.user?.id ?? 'unknown',
name: response?.user?.name ?? 'Guest',
email: response?.user?.email,
avatar: response?.user?.profile?.avatar ?? '/default-avatar.png',
verified: response?.user?.verified ?? false
};
// Вызвать калбэк если он есть
response?.onSuccess?.();
return user;
}
6. Разница между ?, ??, ?.
// ? — ternary (условный оператор)
const result = condition ? trueValue : falseValue;
// ?? — nullish coalescing
const value = maybeNull ?? defaultValue;
// ?. — optional chaining
const nested = obj?.property?.nested?.value;
// ?. для методов
obj?.method?.();
// ?. для индексов
array?.[0];
7. Когда я использую каждый
// Optional chaining (?.) — для безопасного доступа
const email = user?.email; // Частое использование
// Nullish coalescing (??) — для дефолтных значений
const theme = preferences?.theme ?? 'light';
// Ternary (?) — для условного отображения
return isLoading ? <Spinner /> : <Content />;
Производительность
// Optional chaining имеет небольшой overhead,
// но его незначительно
// Быстро
const a = obj.prop;
// Практически так же быстро (браузеры оптимизировали)
const b = obj?.prop;
// Всегда используй optional chaining,
// так как безопасность важнее мизерного overhead
Поддержка браузерами
- Optional Chaining (?.) — Chrome 80+, Firefox 74+, Safari 13.1+
- Nullish Coalescing (??) — Chrome 80+, Firefox 75+, Safari 13.1+
- Ternary (?) — все браузеры (давно добавлено)
Для старых браузеров используй polyfills или transpilation (Babel).
Главное правило
Используй ?. когда нужен безопасный доступ к вложенным свойствам.
Используй ?? когда нужно дефолтное значение для null/undefined.
Используй ? : для условного отображения/вычисления.
Эти операторы делают код безопаснее и более выразительным.