Строка — самый частый источник «значений, которых нет». Юзер оставил поле пустым — пришла "". Тот же юзер напечатал null в текстовое поле — пришла строка "null". Из URL ?filter= — снова пустая строка. Семантически во всех трёх случаях значения нет, но JavaScript видит обычные строки. Чтобы дальше работать с этим как с настоящим отсутствием, нужна конверсия.
Задача: проверить условие на строке и, если оно сработало, заменить её на null, undefined или (реже) NaN.
Когда это нужно
- Чистка ввода формы. Перед отправкой на бэк пустые поля стоит явно занулить: { city: "" } и { city: null } могут трактоваться по-разному (особенно если у поля есть валидатор «обязательно»).
- Восстановление из localStorage. localStorage.getItem('missing') на отсутствующем ключе вернёт null, но если когда-то сохранил "null" строкой — при чтении получишь буквальный текст. Нормализуем.
- URL-параметры. URLSearchParams.get('q') для отсутствующего ключа — null, но для ?q= — пустая строка. Часто оба случая хочется обрабатывать одинаково.
- API нормализация. Бэк ждёт "discount": null для «скидки нет», но фронт собирает значение из текстового поля. Перед отправкой превращаем "" в null.
- Сравнения и filtering. Удалить из списка все элементы «без имени» легче, когда они все имеют name === null, а не «иногда null, иногда пустая строка».
Способ 1: тернарный оператор с проверкой длины
Самый компактный и понятный способ — проверить, осталось ли что-то после trim():
let city = userInput.trim();
city = city.length ? city : null;
console.log(''.trim().length); // 0 → null
console.log(' '.trim().length); // 0 → null (только пробелы)
console.log('Берлин'.trim().length); // 6 → "Берлин"
.trim() убирает пробельные символы (включая табы и переносы строк) по краям строки. Если после этого length равно нулю — считаем, что значения нет. Иначе оставляем как есть.
Альтернатива — проверять не .length, а саму строку. "" — falsy, любая непустая — truthy:
let city = userInput.trim();
city = city || null;
// то же через ?? — но ?? тут не подходит, потому что пустая строка не nullish
Запись с || читается ещё короче, но имеет нюанс: она работает только если «нет данных» всегда falsy. Если в логике «0» или строка "0" — валидные значения, — первая запись через .length безопаснее.
Способ 2: маппинг через объект
Иногда нужно превратить в спецзначение не пустую строку, а буквальные слова "null", "undefined", "nan" — такое часто прилетает из URL или старых API.
const SPECIAL_VALUES = {
'null': null,
'undefined': undefined,
'nan': NaN,
'': null,
};
function parseValue(str) {
const key = String(str).trim().toLowerCase();
return key in SPECIAL_VALUES ? SPECIAL_VALUES[key] : str;
}
parseValue("null") // null
parseValue("UNDEFINED") // undefined
parseValue("NaN") // NaN
parseValue("") // null
parseValue("Берлин") // "Берлин"
Преимущество объекта-маппинга — декларативность: добавить новый случай (например, "none" → null) — одна строка. Минус — чуть больше кода для простой задачи.
Способ 3: JSON.parse для строгих случаев
Если приходящая строка должна быть валидным JSON-значением, можно использовать JSON.parse — он распознает "null" и числа автоматически.
JSON.parse("null") // null
JSON.parse("42") // 42
JSON.parse("true") // true
JSON.parse('"hello"') // "hello"
JSON.parse("hello") // SyntaxError — не валидный JSON
// безопасная обёртка:
function tryParse(str) {
try {
return JSON.parse(str);
} catch {
return str;
}
}
tryParse("null") // null
tryParse("42") // 42
tryParse("Берлин") // "Берлин" (не валидный JSON — вернули как есть)
Этот способ хорош, когда работаешь с уже как-бы-сериализованными значениями — например, читаешь свои же данные из localStorage, которые туда положил через JSON.stringify. Тогда обратное чтение через JSON.parse корректно восстановит и null, и числа, и булевые.
Внимание: JSON.parse("undefined") бросит SyntaxError — undefined не входит в спецификацию JSON.
Подводные камни
Boolean("") — false, но Boolean(" ") — true. Пустая строка — falsy, строка из одного пробела — уже truthy (не пустая по длине). Всегда применяй .trim() перед проверками.
Регистр имеет значение. "Null", "NULL" и "null" — три разные строки. При маппинге всегда нормализуй через .toLowerCase() или используй регулярное выражение с флагом i.
Не-видимые пробельные символы. Юникод содержит много пробельных символов, помимо обычного ' ': неразрывный ' ', табы, zero-width space. Большинство ловит .trim(), но не все. Для тотальной нормализации используют регэксп .replace(/^\s+|\s+$/g, '') — \s в JS-регэкспах поведенчески шире, чем у .trim().
HTML-сущности. Если строка пришла из innerHTML, в ней могут быть (неразрывный пробел в виде сущности). Сначала декодируй, потом проверяй на «пустоту». Браузер декодирует автоматически при чтении textContent, но не innerHTML.
String(null) — это "null". Если случайно превратишь null в строку (например, через шаблонный литерал `${value}`), а потом проверишь «пустая или нет» — пройдёт, как непустая. Превращай в спецзначение до того, как значение успело попасть в шаблон или конкатенацию.