Справочник по JavaScript (Handbook)
Честное, понятное и современное руководство по JavaScript. Объясняем сложные концепции простым языком: без непонятной академической терминологии, но с упором на то, как всё работает на самом деле.
- 1. Переменные, типы данных и почему `==` — это ловушка
- 2. Видимость переменных и Замыкания (Closures) — просто о сложном
- 3. Контекст `this` и функции — где теряется значение?
- 4. Асинхронность и Event Loop — как JS выполняет задачи
- 5. Промисы (Promises) и async/await — работа с сетью без боли
- 6. Объекты, Массивы и современные методы (ES6+)
1. Переменные, типы данных и почему `==` — это ловушка
В JavaScript есть два вида данных: примитивы (простые значения вроде чисел и строк) и объекты (сложные структуры вроде массивов и функций).
- Примитивы:
number,string,boolean,null,undefined,symbol,bigint. Копируются по значению. - Объекты: Массивы
[], Объекты{}, Функции. Копируются по ссылке (как адрес на папку в компьютере).
Как правильно объявлять переменные
Забудьте про var — это устаревший инструмент с кучей подводных камней. Используйте современный подход:
const— для всего по умолчанию. Значение нельзя перезаписать.let— только если значение переменной действительно будет меняться (например, счетчик в цикле).
// Сравнение: строгое (===) против нестрогого (==)
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** (событийный цикл).
- Сначала выполняется весь обычный синхронный код.
- Затем выполняются Микрозадачи (Promise, async/await).
- Только потом выполняются Макрозадачи (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