Значения по умолчанию в JavaScript: от базовых подходов до современного синтаксиса
Значения по умолчанию в JavaScript: обзор подходов
В JavaScript нередко возникает необходимость задать значение по умолчанию для переменной, параметра функции или свойства объекта. Это помогает избежать ошибок и делает код более предсказуемым. Рассмотрим самые распространенные способы, от классических до современных, с примерами и разбором типичных проблем.
Основное решение: оператор нулевого слияния (??)
Оператор ?? возвращает правый операнд только тогда, когда левый операнд равен null или undefined. Это идеально подходит для случаев, когда нужно заменить отсутствующее значение, но не трогать другие ложные значения (0, пустую строку, false).
let count = null;
let defaultCount = count ?? 10; // 10, так как count === null
let name = '';
let defaultName = name ?? 'Аноним'; // '', так как '' не null и не undefined
let age;
let defaultAge = age ?? 18; // 18, так как age undefinedJavascript вывести (javascript: вывод данных)
Пояснение: если count равен null или undefined, используется значение 10. Если name - пустая строка, она остаётся пустой, так как ?? не считает её «неопределённой».
Типичная ошибка: путать ?? с ||. Оператор || реагирует на любые ложные значения, что может привести к нежелательной подмене нуля или пустой строки.
Цель: заменять только null или undefined, оставляя остальные значения без изменений.
Как задать значение по умолчанию, если переменная ложная?
Классический способ - логическое ИЛИ (||).
let score = 0;
let displayScore = score || 100; // 100, так как 0 считается ложнымDefaults js (javascript: значения по умолчанию)
Пояснение: || возвращает первый истинный операнд. Если score ложный (0, '', false, null, undefined, NaN), будет взято 100. Иногда это нежелательно, если 0 - допустимое значение.
Проблема: нулевое значение, пустая строка или false могут быть корректными данными, но || их заменяет.
Цель: быстрое присваивание по умолчанию, когда ложные значения гарантированно не являются ожидаемыми.
Как явно проверить условие и выбрать значение?
Тернарный оператор ? : позволяет гибко задать условие.
let value = someValue !== undefined ? someValue : 'default';
If else javascript (javascript: условный оператор if...else)
Пояснение: проверяется строгое неравенство с undefined. Можно также проверять на null или другие условия.
Ошибка: забыть проверку на null отдельно, если требуется исключить оба.
Цель: когда нужна произвольная логика выбора, не ограниченная только ложностью.
Как упростить установку значений для отсутствующих аргументов?
Параметры функций по умолчанию (ES6+).
function greet(name = 'Гость') {
console.log(`Привет, ${name}!`);
}
greet(); // Привет, Гость!
greet('Анна'); // Привет, Анна!Format js (javascript: форматирование)
Пояснение: если аргумент не передан или равен undefined, подставляется значение по умолчанию. null не считается отсутствующим и останется null.
Типичная ошибка: передача null - значение не заменится на умолчание. Нужно предусмотреть дополнительную обработку.
Цель: избавиться от ручных проверок внутри функции, улучшить читаемость.
Как задать значения по умолчанию для свойств объекта при деструктуризации?
Деструктуризация с умолчаниями работает аналогично параметрам функций.
const user = { name: 'Иван' };
const { name, age = 25 } = user;
console.log(age); // 25, так как age отсутствует в userПояснение: извлекаем свойство age, и если его нет, присваивается 25.
Ошибка: если свойство существует, но равно undefined или null, значение по умолчанию не сработает для null - только для undefined.
Цель: компактная инициализация переменных из объекта.
Как объединить объекты с приоритетом значений по умолчанию?
Метод Object.assign или оператор spread (...).
const defaults = { color: 'синий', size: 'M' };
const userPrefs = { color: 'красный' };
const merged = { ...defaults, ...userPrefs };
console.log(merged); // { color: 'красный', size: 'M' }Пояснение: сначала раскладывается объект с умолчаниями, затем пользовательские настройки перезаписывают совпадающие ключи.
Проблема: поверхностное копирование - вложенные объекты не сливаются, а заменяются.
Цель: создание конфигураций с приоритетом пользовательских данных.
Как проверить, что значение именно undefined, а не другое ложное?
Прямая проверка typeof или строгое сравнение с undefined.
let data;
let result = (typeof data !== 'undefined') ? data : 'no data';
// или
let result2 = (data !== undefined) ? data : 'no data';Пояснение: оператор typeof безопасен, так как не выбрасывает ошибку для необъявленных переменных.
Ошибка: путать undefined с null. Если требуется заменить оба, нужно проверять data == null (с нестрогим равенством).
Цель: точное выделение только отсутствующих значений.
Расширенные примеры использования значений по умолчанию
Ниже представлены более сложные и неочевидные комбинации подходов, которые могут пригодиться в реальных проектах.
Комбинирование ?? и ||
function getConfig(opts) {
const timeout = opts.timeout ?? 1000; // null/undefined -> 1000
const retries = opts.retries || 3; // ложное -> 3 (но 0 тоже станет 3)
return { timeout, retries };
}
console.log(getConfig({ timeout: 0, retries: 0 })); // { timeout: 0, retries: 3 }{ timeout: 0, retries: 3 }Пояснение: для timeout используется ??, поэтому 0 остаётся, а для retries через || 0 заменяется на 3. Это может быть неожиданным, если 0 допустим.
Вложенные умолчания при деструктуризации объектов
const data = { user: { name: 'Мария' } };
const { user: { name, role = 'user', permissions: { read = true, write = false } = {} } } = data;
console.log(name, role, read, write); // Мария user true falseМария user true false
Пояснение: глубокое вложение с умолчаниями на каждом уровне. Если свойство permissions отсутствует, используется пустой объект, затем read и write получают свои умолчания.
Динамическое значение по умолчанию через функцию
function getDefaultId() {
return Math.random().toString(36).substring(2, 8);
}
function createUser({ id = getDefaultId(), name } = {}) {
return { id, name };
}
console.log(createUser({ name: 'Олег' }));
console.log(createUser());{ id: 'a1b2c3', name: 'Олег' }
{ id: 'x9y8z7', name: undefined }Пояснение: значение по умолчанию может быть результатом вызова функции. Это удобно, когда умолчание генерируется каждый раз заново (уникальный ID, timestamp).
Цепочка с опциональным вызовом (?. ) и ??
const user = { profile: { settings: null } };
const theme = user?.profile?.settings?.theme ?? 'светлая';
console.log(theme); // светлаясветлая
Пояснение: опциональная цепочка безопасно обходит отсутствующие или null-свойства, а ?? даёт конечное значение по умолчанию, если результат - undefined или null.
Значения по умолчанию в массивах через деструктуризацию
const colors = ['красный'];
const [first, second = 'синий', third = 'зелёный'] = colors;
console.log(first, second, third); // красный синий зелёныйкрасный синий зелёный
Пояснение: при деструктуризации массива можно задать умолчания для элементов, которых нет.
Использование defaults для классов (конструктор с объектом параметров)
class Car {
constructor({ brand = 'Tesla', model = 'Model 3', year = 2024 } = {}) {
this.brand = brand;
this.model = model;
this.year = year;
}
}
const myCar = new Car({ brand: 'BMW' });
console.log(myCar); // Car { brand: 'BMW', model: 'Model 3', year: 2024 }Car { brand: 'BMW', model: 'Model 3', year: 2024 }Пояснение: параметры конструктора с умолчаниями и полным объектом по умолчанию - распространённый паттерн для удобной конфигурации.