Ошибки в функциях часто появляются не из-за самой логики, а из-за входных данных. В функцию пришло undefined, строка вместо числа, пустое значение или результат вычислений стал NaN. Если такие случаи не учитывать, код начинает вести себя непредсказуемо.
1) Undefined: аргумент не передан или значение не найдено
Аргумент не передали
Если аргумент не передан, параметр становится undefined.
function greet(name) {
return "Hello, " + name;
}
console.log(greet()); // "Hello, undefined"
Простой способ защититься - значение по умолчанию:
function greet(name = "Guest") {
return "Hello, " + name;
}
console.log(greet()); // "Hello, Guest"
Доступ к свойству у undefined
Если попытаться обратиться к свойству у undefined или null, будет ошибка времени выполнения.
function getUserName(user) {
return user.name.toUpperCase();
}
try {
console.log(getUserName(undefined));
} catch (e) {
console.log(e.name); // "TypeError"
}
Один из базовых подходов - guard clause:
function getUserNameSafe(user) {
if (!user) return null;
if (!user.name) return null;
return String(user.name).toUpperCase();
}
console.log(getUserNameSafe(undefined)); // null
2) NaN: вычисление не получилось
NaN означает “not a number”. Он появляется, когда JavaScript не смог получить число.
const n = Number("x");
console.log(n); // NaN
Проблема в том, что NaN “заражает” арифметику:
console.log(NaN + 1); // NaN
console.log(NaN * 10); // NaN
Проверка NaN
Для надежной проверки используется Number.isNaN.
const value = Number("x");
console.log(Number.isNaN(value)); // true
console.log(Number.isNaN("x")); // false
Пример: функция, которая возвращает null вместо NaN
function toNumber(value) {
const n = Number(value);
if (Number.isNaN(n)) return null;
return n;
}
console.log(toNumber("10")); // 10
console.log(toNumber("x")); // null
3) Неверный тип: строка вместо числа, объект вместо строки
JavaScript позволяет передать в функцию что угодно. Если тип не тот, ошибки бывают двух видов:
- код ломается (TypeError)
- код работает, но результат неверный (тихая ошибка)
TypeError: метода нет
function normalize(text) {
return text.trim().toLowerCase();
}
try {
console.log(normalize(10));
} catch (e) {
console.log(e.name); // "TypeError"
}
Защита через явную проверку:
function normalizeSafe(text) {
if (typeof text !== "string") return null;
return text.trim().toLowerCase();
}
console.log(normalizeSafe(" Hi ")); // "hi"
console.log(normalizeSafe(10)); // null
Тихая ошибка: неявные преобразования
Иногда тип “не тот”, но JavaScript пытается преобразовать значения.
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
console.log(add("2", 3)); // "23"
Если функция предполагает числа, лучше приводить к числу и проверять результат:
function addNumbers(a, b) {
const x = Number(a);
const y = Number(b);
if (Number.isNaN(x) || Number.isNaN(y)) return null;
return x + y;
}
console.log(addNumbers("2", 3)); // 5
console.log(addNumbers("x", 3)); // null
4) Ошибки return: undefined вместо ожидаемого значения
Иногда функция “должна вернуть”, но return есть не во всех ветках.
function getLabel(status) {
if (status === "ok") return "Done";
}
console.log(getLabel("fail")); // undefined
Исправление - вернуть значение по умолчанию:
function getLabelSafe(status) {
if (status === "ok") return "Done";
return "Unknown";
}
console.log(getLabelSafe("fail")); // "Unknown"
5) Что проверять в первую очередь
Часто достаточно нескольких базовых проверок:
- аргументы не
undefinedи неnull - тип соответствует ожиданиям (
typeof) - для чисел: значение не
NaNи, если нужно, конечное (Number.isFinite) - если функция возвращает значение,
returnесть во всех ветках
Пример с несколькими проверками:
function calcDiscount(price, percent) {
if (!Number.isFinite(price)) return null;
if (!Number.isFinite(percent)) return null;
if (percent < 0 || percent > 100) return null;
return price - (price * percent) / 100;
}
console.log(calcDiscount(200, 10)); // 180
console.log(calcDiscount("x", 10)); // null
Что стоит запомнить
undefinedчасто появляется из-за пропущенного аргумента или отсутствующего значения.NaN- сигнал, что число получить не удалось; проверка делается черезNumber.isNaN.- Неверные типы приводят к TypeError или к тихим ошибкам из-за
+и других преобразований. - Guard clauses и проверки входных данных делают функции предсказуемыми.