Вот пример функии:
// users.js
export const filterAdults = (users) => {
return users.filter(user => user.age >= 18);
};
Как ее переписать чтобы обрабатывался аргумент пустая строка.
В вашем примере функция filterAdults ожидает массив объектов, но если в неё передать пустую строку (или null), JavaScript выдаст ошибку TypeError: users.filter is not a function. Это происходит потому, что у строк нет метода .filter().
Вот как можно переписать эту функцию, чтобы она была надежной («пуленепробиваемой»).
1. Простой способ (Проверка на наличие)
Самый быстрый вариант — проверить, существует ли users и является ли он массивом.
JavaScript
export const filterAdults = (users) => {
// Если users — пустая строка, null или не массив, возвращаем пустой массив
if (!Array.isArray(users)) {
return [];
}
return users.filter(user => user && user.age >= 18);
};
2. Современный способ (Значение по умолчанию)
Если вы хотите защититься только от undefined, можно задать значение по умолчанию. Но для пустой строки это не сработает, поэтому лучше комбинировать подходы:
JavaScript
export const filterAdults = (users = []) => {
// Проверяем, что пришел именно массив
if (!Array.isArray(users)) return [];
return users.filter(user => user?.age >= 18);
};
Здесь user?.age (optional chaining) защищает от ситуации, если внутри массива вместо объекта окажется null.
Почему это важно? (Логика обработки)
При написании функций важно понимать, что именно должна возвращать функция в случае некорректных данных. Обычно лучше возвращать пустой массив [], чем null или ошибку, чтобы остальной код (например, цикл в React) не сломался.
3. Профессиональный подход (Guard Clauses)
В большой разработке используют так называемые «защитные условия» (Guard Clauses) в начале функции. Это делает код чище, так как основная логика не прячется внутри if/else.
JavaScript
export const filterAdults = (users) => {
// 1. "Вышибаем" плохие данные сразу
const isInvalid = !users || !Array.isArray(users);
if (isInvalid) return [];
// 2. Спокойно работаем с данными, зная, что это массив
return users.filter(user => {
// Дополнительная проверка: есть ли у пользователя поле age
return typeof user.age === 'number' && user.age >= 18;
});
};
Что изменилось:
- Безопасность: Функция больше никогда не вызовет «падение» программы.
- Предсказуемость: Она всегда возвращает массив (либо с данными, либо пустой).
- Гибкость: Мы добавили проверку
typeof user.age, чтобы строки или случайные объекты не испортили результат.
Я не понимаю как прочитать «user?.age» и как это все же работает ?
Сравнение «Раньше» и «Сейчас»
| Что проверяем | Раньше (ES5/ES6) | Сейчас (ES2020+) |
| Безопасный доступ | user && user.age | user?.age |
| Значение по умолчанию | user.age !== undefined ? user.age : 0 | user?.age ?? 0 |
Итог
Современный вариант делает ровно то же самое, что и длинный user?.age >= 18if (user != null && user.age >= 18), но под капотом. JavaScript сам берет на себя рутину по проверке на null и undefined.
1. Как работает user && user.age
Этот оператор проверяет «правдивость» (truthiness) левой части.
- Если
user— это любая «ложь» (null,undefined,0,false,""), то выполнение прервется и вернется это самое «ложное» значение. - В чем проблема: Если
userбудет равен, например, числу0, то проверка0 && 0.ageостановится на нуле, хотя технически у числа тоже можно пытаться вызвать свойства (хоть это и бессмысленно).
2. Как работает user?.age (Optional Chaining)
Этот оператор строже. Он проверяет только на «пустоту»: null или undefined.
- Если
user— это0,falseили""(пустая строка), оператор?.не остановится. Он посчитает, что объект существует, и попытается найти у него.age.
Наглядное сравнение на примерах
Представь, что в переменную user попало что-то странное:
| Значение user | user && user.age | user?.age | Разница |
{ age: 20 } | 20 | 20 | Одинаково |
null | null | undefined | Одинаково (оба «ложные») |
undefined | undefined | undefined | Одинаково |
0 (число) | 0 | Ошибка! | Разница! |
нет сокращения для «ИЛИ» user || user.age