Антипаттерны: чего избегать

Антипаттерн — повторяющийся подход к решению задачи, который выглядит разумным, но на практике приводит к проблемам: трудноуловимым багам, низкой производительности, плохой поддерживаемости.

Зачем нужно

Знание антипаттернов позволяет распознавать опасные практики в своём и чужом коде до того, как они превратятся в баги или технический долг. Это важная часть code review и написания качественного JavaScript.

Где используется

Знание антипаттернов применяется при любом написании JS: в функциях, работе с DOM, асинхронном коде, ООП.

Антипаттерны в JavaScript

1. Загрязнение глобального пространства имён

// Плохо
var user = { name: 'Иван' }; // глобальная переменная
function loadData() { ... }   // глобальная функция

// Хорошо — оборачивать в модуль или IIFE
const App = (function {
  const user = { name: 'Иван' };
  function loadData() { ... }
  return { loadData };
});

2. Расширение встроенных прототипов

// Плохо: может сломать сторонние библиотеки
Array.prototype.last = function { return this[this.length - 1]; };

// Хорошо: вспомогательная функция
function last(arr) { return arr[arr.length - 1]; }

3. eval

// Плохо: медленно, опасно, трудно отлаживать
const code = 'console.log("Привет")';
eval(code);

// Хорошо: явный вызов функции
function doSomething() { console.log('Привет'); }
doSomething;

4. Callback Hell

// Плохо: «пирамида смерти»
getData(function(a) {
  getMoreData(a, function(b) {
    getEvenMoreData(b, function(c) {
      console.log(c);
    });
  });
});

// Хорошо: async/await
async function main() {
  const a = await getData;
  const b = await getMoreData(a);
  const c = await getEvenMoreData(b);
  console.log(c);
}

5. Прямая мутация аргументов функции

// Плохо: мутирует переданный объект неожиданно
function addDiscount(order) {
  order.price *= 0.9; // изменяет оригинал!
  return order;
}

// Хорошо: возвращаем новый объект
function addDiscount(order) {
  return { ...order, price: order.price * 0.9 };
}

6. Магические числа и строки

// Плохо
if (status === 3) { ... }

// Хорошо
const STATUS = { PENDING: 1, ACTIVE: 2, CLOSED: 3 };
if (status === STATUS.CLOSED) { ... }

7. Слишком длинные функции

// Плохо: функция делает всё сразу (200 строк)
function processOrder(order) {
  // валидация, расчёт стоимости, применение скидок,
  // сохранение в БД, отправка уведомления — всё в одном
}

// Хорошо: разбить на маленькие функции с одной ответственностью
function validateOrder(order) { ... }
function calculateTotal(order) { ... }
function applyDiscounts(order) { ... }

Частые ошибки

  • Использование == вместо === — нестрогое равенство делает неявные преобразования типов (0 == ''true); всегда используйте ===.
  • Синхронные операции в асинхронном контексте — тяжёлые вычисления в обработчиках событий блокируют поток.
  • Игнорирование результатов промисов — незакрытые Promise без .catch создают необработанные ошибки.

Связанные темы

Ресурсы