Топ ошибок начинающих JavaScript разработчиков: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему JavaScript — это минное поле для новичков?

JavaScript (особенно в среде Node.js) — это язык с огромным количеством подводных камней. Его динамическая природа и асинхронность часто ставят в тупик даже тех, кто уже освоил Python или Java. Кажется, что код работает, но в самый неподходящий момент вылетает undefined is not a function или NaN.

В этой статье мы разберем топ ошибок начинающих JavaScript разработчиков — от банальных опечаток до глубоких концептуальных ловушек. Каждый пункт будет с реальным примером на Node.js и объяснением, как это исправить. Поехали!


1. Путаница с var, let и const (Область видимости)

Самая частая ошибка новичка — использование var вместо let или const. В Node.js (особенно в строгом режиме) это приводит к неожиданному поведению из-за всплытия (hoisting).

Проблема

Переменные, объявленные через var, имеют функциональную, а не блочную область видимости.

// Пример ошибки
function testLoop() {
  for (var i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 100);
  }
}
testLoop(); // Выведет: 5, 5, 5, 5, 5 (а не 0,1,2,3,4)

Решение

Всегда используйте let для изменяемых переменных и const для неизменяемых. var лучше не использовать вообще.

// Исправленный код
function testLoopFixed() {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 100);
  }
}
testLoopFixed(); // Выведет: 0, 1, 2, 3, 4

2. Игнорирование асинхронности (Callback Hell и Promise)

Node.js построен на асинхронности. Попытка писать код так, как будто он выполняется последовательно (как в Python), приводит к Callback Hell и гонке данных.

Проблема

Вложенные колбэки и попытка получить данные до их загрузки.

// Плохо: Callback Hell
const fs = require('fs');

fs.readFile('file1.txt', 'utf8', (err, data1) => {
  fs.readFile('file2.txt', 'utf8', (err, data2) => {
    // ... и так далее
    console.log(data1 + data2);
  });
});

Решение

Используйте async/await и Promise.all(). Это делает код линейным и читаемым.

// Хорошо: async/await
const fs = require('fs').promises;

async function readFiles() {
  try {
    const [data1, data2] = await Promise.all([
      fs.readFile('file1.txt', 'utf8'),
      fs.readFile('file2.txt', 'utf8')
    ]);
    console.log(data1 + data2);
  } catch (err) {
    console.error('Ошибка чтения файла:', err);
  }
}
readFiles();

3. Непонимание контекста this

В JavaScript this определяется не тем, где функция написана, а тем, как она вызвана. В Node.js (вне методов объекта) this ссылается на пустой объект {}, а не на global (как в браузере).

Проблема

Потеря контекста при передаче метода как колбэка.

const user = {
  name: 'Алексей',
  greet() {
    console.log(`Привет, ${this.name}!`);
  }
};

setTimeout(user.greet, 1000); // Выведет: "Привет, undefined!"

Решение

Используйте стрелочную функцию (она не создает свой this) или метод .bind().

// Вариант 1: bind
setTimeout(user.greet.bind(user), 1000);

// Вариант 2: стрелочная функция
setTimeout(() => user.greet(), 1000); // "Привет, Алексей!"

4. Сравнение с == вместо ===

Оператор == приводит типы, что часто дает неожиданные результаты. В Node.js это особенно опасно при валидации данных.

Проблема

// Неожиданные истины
console.log(0 == false);    // true
console.log('' == false);   // true
console.log([] == false);   // true
console.log(null == undefined); // true

Решение

Всегда используйте строгое сравнение === и !==. Это исключает приведение типов.

// Безопасное сравнение
console.log(0 === false);    // false
console.log('' === false);   // false
console.log([] === false);   // false
console.log(null === undefined); // false

5. Замыкания в циклах (старая школа)

Даже с let новички умудряются наступить на грабли с замыканиями, если используют var или забывают о создании новой копии переменной.

Проблема

// Классическая ошибка с var
var funcs = [];
for (var i = 0; i < 3; i++) {
  funcs.push(function() { console.log(i); });
}
funcs.forEach(fn => fn()); // 3, 3, 3

Решение

Используйте let (создает новую привязку на каждой итерации) или немедленно вызываемую функцию (IIFE) для старых стандартов.

// Исправлено с let
const funcsFixed = [];
for (let j = 0; j < 3; j++) {
  funcsFixed.push(() => console.log(j));
}
funcsFixed.forEach(fn => fn()); // 0, 1, 2

6. Му

Блоги

Рекомендаций по книгам