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

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

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

Начать курс

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

JavaScript — язык, который одновременно прост для входа и сложен для глубокого понимания. Многие начинающие разработчики, приходя в Node.js, сталкиваются с неожиданными багами, которые кажутся иррациональными. Проблема часто кроется не в логике алгоритма, а в фундаментальных особенностях языка: асинхронности, неочевидном поведении this и тонкостях областей видимости.

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

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

Одна из самых частых проблем — использование устаревшего var и непонимание разницы между let и const.

Проблема с var и всплытием (Hoisting)

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

// ❌ Ошибка: undefined вместо ReferenceError
console.log(myVar); // undefined (ошибки нет!)
var myVar = 5;

// ✅ Правильно: let или const
console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = 5;

Замыкания в цикле

Классическая ошибка с var в циклах:

// ❌ Неверно: все колбэки выведут 3
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Вывод: 3, 3, 3

// ✅ Исправление: let создает новую привязку для каждой итерации
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Вывод: 0, 1, 2

Совет: Забудьте про var в современном JavaScript. Используйте const по умолчанию и let, если переменная будет переназначаться.

2. Асинхронный ад: Callback Hell и неправильная работа с промисами

Node.js построен на асинхронности. Новички часто пытаются получить результат асинхронной функции синхронно, что приводит к undefined.

Игнорирование промисов

// ❌ Ошибка: функция возвращает undefined
function getUserData(userId) {
    const user = database.findUser(userId); // Асинхронная операция
    return user; // undefined, так как данные еще не пришли
}

// ✅ Правильно: возвращаем промис
async function getUserData(userId) {
    const user = await database.findUser(userId);
    return user;
}

Callback Hell (Ад колбэков)

Вложенные колбэки делают код нечитаемым и сложным для поддержки:

// ❌ Плохо: пирамида колбэков
fs.readFile('a.txt', (err, dataA) => {
    fs.readFile('b.txt', (err, dataB) => {
        fs.writeFile('c.txt', dataA + dataB, (err) => {
            console.log('Готово!');
        });
    });
});

// ✅ Хорошо: async/await
async function mergeFiles() {
    const dataA = await fs.promises.readFile('a.txt');
    const dataB = await fs.promises.readFile('b.txt');
    await fs.promises.writeFile('c.txt', dataA + dataB);
    console.log('Готово!');
}

Золотое правило: Если видите вложенность глубже 2 уровней — рефакторите через async/await.

3. Загадочный this: потеря контекста

В JavaScript this определяется тем, как вызвана функция, а не где она объявлена. Это главная причина путаницы.

Потеря this в методах объекта

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

// ✅ Работает
user.greet(); // Привет, Алекс

// ❌ Ошибка: this потерян
const greetFunc = user.greet;
greetFunc(); // Привет, undefined

// ✅ Исправление: bind
const boundGreet = user.greet.bind(user);
boundGreet(); // Привет, Алекс

this в колбэках (Node.js)

class Logger {
    constructor() {
        this.logs = [];
    }

    // ❌ Ошибка: this указывает на глобальный объект
    addLogsBad(arr) {
        arr.forEach(function(item) {
            this.logs.push(item); // TypeError: Cannot read property 'push' of undefined
        });
    }

    // ✅ Исправление: стрелочная функция
    addLogsGood(arr) {
        arr.forEach((item) => {
            this.logs.push(item); // this берется из внешнего контекста
        });
    }
}

Лайфхак: Если вы используете .bind(this) или const self = this — перепишите на стрелочные функции. Они не создают собственный this.

4. Мутация объектов и массивов: неожиданные побочные эффекты

В JavaScript объекты и массивы передаются по ссылке. Новички часто мутируют исходные данные, не создавая копии.

Случайное изменение исходного массива

// ❌ Ошибка: мутация исходного массива
function removeItem(arr, index) {
    arr.splice(index, 1); // Изменяет оригинальный массив!
    return arr;
}

const original = [1, 2, 3];
const modified = removeItem(original, 1);
console.log(original); // [1, 3] — оригинал изменен!

// ✅ Правильно: создаем копию
function removeItemSafe(arr, index) {
    return arr.filter((_, i) => i !== index);
}

const original2 = [1, 2, 3];
const modified2 = removeItemSafe(original2, 1);
console.log(original2); // [1, 2, 3] — оригинал сохранен

Неглубокое копирование объектов

const user = { name: 'Иван', address: { city                

Блоги

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