Learn JavaScript

Ошибки в функциях: undefined, NaN и неверные типы

Ошибки в функциях часто появляются не из-за самой логики, а из-за входных данных. В функцию пришло 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 и проверки входных данных делают функции предсказуемыми.