Бывают случаи, когда пустой массив [] в коде — не «коллекция из нуля элементов», а сигнал «тут ничего нет». Чтобы соседний код увидел это однозначно, имеет смысл превратить пустой массив в null или undefined.
Главная сложность: массив — объект, и прямой Boolean([]) возвращает true, что обычно не то, чего ожидаешь. Поэтому проверку «есть ли что-то» делают через .length, а не через прямое приведение.
Когда это нужно
- Нормализация ответа API. Бэк прислал { items: [] }, но соседний компонент проверяет if (data.items) — для него пустой массив всё ещё truthy, и он попытается отрендерить «список из нуля строк» с лишней разметкой. Превратив [] в null, можно показать pure-empty состояние.
- Передача обратно на бэк. Часть API ждёт null для «фильтр не задан» и непустой массив для «применить фильтр». Пустой массив [] может быть интерпретирован как «применить фильтр без значений», что вернёт ноль результатов.
- Default-значения формы. Если поле «теги» никем не заполнялось, хочется отправить tags: undefined (выпадет из JSON), а не tags: [] (бэк решит, что юзер активно очистил поле).
- Проверка осмысленности. В цепочке вычислений result?.items?.length возвращает undefined для отсутствующего result, и 0 для пустого массива. Иногда хочется, чтобы оба случая обрабатывались одинаково.
Способ 1: тернарник с .length
Самый прямой и читаемый способ. Проверяем длину — если ноль, заменяем на спецзначение.
let items = [];
let result = items.length ? items : null;
console.log(result); // null
let users = ['Анна', 'Сергей'];
result = users.length ? users : null;
console.log(result); // ['Анна', 'Сергей']
// для undefined вместо null:
result = items.length ? items : undefined;
В JavaScript ноль — falsy, поэтому items.length ? items : null работает: если длина 0 — false, идём в else-ветку.
Способ 2: filter + длина
Если массив может содержать «пустые» элементы (null, undefined, пустые строки), а считать осмысленными только «настоящие», — сначала фильтруем, потом проверяем.
let raw = [null, undefined, '', 0, 'tag'];
// «есть ли хотя бы один truthy-элемент»
let cleaned = raw.filter(Boolean);
let result = cleaned.length ? cleaned : null;
console.log(result); // ['tag']
// если 0 — валидное значение, фильтруем явно:
let cleaned2 = raw.filter(x => x != null && x !== '');
let result2 = cleaned2.length ? cleaned2 : null;
console.log(result2); // [0, 'tag']
Лайфхак filter(Boolean) — короткая запись: проходит каждый элемент через Boolean(x), и оставляет только truthy. Идиома известная, но имеет нюанс: ноль и пустая строка тоже выпадают.
Способ 3: deep-empty проверка
Иногда массив технически не пустой, но «по смыслу» пустой — например, состоит из пустых объектов [{}, {}]. Если в логике это эквивалентно «ничего», нужна более глубокая проверка.
function isMeaningfullyEmpty(arr) {
if (!Array.isArray(arr) || arr.length === 0) return true;
return arr.every(item => {
if (item == null) return true; // null/undefined
if (typeof item === 'string') return item.trim() === ''; // пустые строки
if (typeof item === 'object') return Object.keys(item).length === 0; // пустые объекты
return false;
});
}
let data = [{}, {}, null];
let result = isMeaningfullyEmpty(data) ? null : data;
console.log(result); // null
Это нишевый кейс — обычно достаточно простой проверки на .length. Но при работе со старыми API, которые присылают «структурно-пустые» коллекции, такая обёртка экономит много рутины.
Подводные камни
Boolean([]) — true. Самая знаменитая ловушка с массивами. Объекты всегда truthy, и пустой массив — не исключение. Поэтому никогда не пишут if (arr) для проверки «есть ли элементы», — только if (arr.length).
if ([]) {
console.log('сюда зайдёт всегда'); // true
}
if ([].length) {
console.log('а сюда — никогда для пустого');
}
[] == false — одновременно true. Если попытаться использовать массив в нестрогом сравнении, JavaScript начинает каскад приведений: массив → строка "" → число 0. И 0 == false даёт true. Парадокс: if ([]) заходит в ветку, но [] == false тоже верно. Поэтому — только .length, никаких ==.
JSON.stringify([]) — это "[]". Пустой массив сериализуется в свою каноническую форму, не пропадает. Если бэк отличает {"tags": []} от {"tags": null} (часто отличает!) — перед отправкой обязательно нормализуй.
Holes-массивы. new Array(3) или [, , ,] — технически имеют length 3, но «настоящих» элементов внутри нет. arr.filter(() => true) вернёт пустой массив — filter пропускает holes. arr.length при этом всё ещё 3. Если есть подозрение, что массив с holes — используй arr.filter(() => true).length.
Псевдо-массивы. document.querySelectorAll('.nothing') вернёт NodeList, а не настоящий массив. У него тоже есть .length, но Array.isArray вернёт false. Если код дальше использует .map или .filter — превращай в настоящий массив через [...nodes] или Array.from(nodes).