Справочник по JavaScript (Handbook)

Честное, понятное и современное руководство по JavaScript. Объясняем сложные концепции простым языком: без непонятной академической терминологии, но с упором на то, как всё работает на самом деле.

Коротко для всех: Неважно, начинающий вы разработчик или уже пишете код — этот справочник разложен по полочкам. Здесь объясняется не только «как написать», но и «почему оно работает именно так».

1. Переменные, типы данных и почему `==` — это ловушка

В JavaScript есть два вида данных: примитивы (простые значения вроде чисел и строк) и объекты (сложные структуры вроде массивов и функций).

Как правильно объявлять переменные

Забудьте про var — это устаревший инструмент с кучей подводных камней. Используйте современный подход:

// Сравнение: строгое (===) против нестрогого (==)
const num = 5;
const str = "5";

console.log(num == str);  // true! JS попытался угадать и привел строку к числу. Это опасно.
console.log(num === str); // false! Разные типы: число и строка. Всегда используйте ===

2. Видимость переменных и Замыкания (Closures)

Замыкание — это когда функция запоминает переменные из того места, где она была создана, даже если саму функцию вызвали совсем в другом месте кода.

Представьте, что функция берёт с собой «рюкзак» с переменными, которые были вокруг неё в момент рождения:

function createCounter() {
    let count = 0; // Эта переменная попадет в "рюкзак" (замыкание)

    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2 (Функция помнит count, хотя createCounter давно завершилась)

3. Контекст `this` и функции — где теряется значение?

Слово this в JavaScript обозначает **«кто вызвал эту функцию прямо сейчас»**. Контекст определяется в момент вызова, а не в момент написания кода.

Как вызываем функцию Чему равен `this` Пример
Как метод объекта Сам объект перед точкой user.sayHi()this = user
Обычный вызов функции undefined (в строгом режиме) или window sayHi()this потерян
Стрелочная функция () => {} Берет this у родителя выше Нет своего this, идеальна для внутренних колбэков
const user = {
    name: "Алексей",
    showName() {
        setTimeout(() => {
            // Стрелочная функция сохраняет `this` от showName (то есть объект user)
            console.log(this.name); // "Алексей"
        }, 100);
    }
};

user.showName();

4. Асинхронность и Event Loop — как JS выполняет задачи

JavaScript **однопоточный**: он может делать только одно дело одновременно. Чтобы сайт не "зависал" во время долгих запросов к серверу, JS использует **Event Loop** (событийный цикл).

Порядок очередей simple-словами:
  1. Сначала выполняется весь обычный синхронный код.
  2. Затем выполняются Микрозадачи (Promise, async/await).
  3. Только потом выполняются Макрозадачи (setTimeout, Click-события).
console.log("1. Старт");

setTimeout(() => console.log("2. Таймер (Макрозадача)"), 0);

Promise.resolve().then(() => console.log("3. Промис (Микрозадача)"));

console.log("4. Финиш");

// Результат в консоли:
// 1. Старт
// 4. Финиш
// 3. Промис (Микрозадача)
// 2. Таймер (Макрозадача)

5. Промисы (Promises) и async/await

Промис (Promise) — это «обещание» вернуть результат позже. Например, когда данные доедут с сервера по сети.

Конструкция async/await — это удобный и красивый способ работать с промисами так, будто это обычный синхронный код.

// Современный и чистый способ получения данных
async function loadUserData(userId) {
    try {
        const response = await fetch(`https://api.example.com/users/${userId}`);
        
        if (!response.ok) {
            throw new Error(`Ошибка сервера: ${response.status}`);
        }

        const data = await response.json();
        return data;
    } catch (error) {
        console.error("Не удалось загрузить пользователя:", error.message);
    }
}

6. Объекты, Массивы и современные методы (ES6+)

В современном JS редкие циклы for заменяются на удобные методы массивов:

const products = [
    { id: 1, title: "Телефон", price: 500 },
    { id: 2, title: "Ноутбук", price: 1200 },
    { id: 3, title: "Чехол", price: 20 }
];

// 1. Фильтрация: оставить только дорогие товары (> 100)
const expensive = products.filter(item => item.price > 100);

// 2. Преобразование: получить только названия
const titles = products.map(item => item.title);

// 3. Деструктуризация (быстрое извлечение данных)
const { title, price } = products[0];
console.log(`Товар: ${title}, Цена: ${price}`); // Товар: Телефон, Цена: 500