- История и философия
- Основы JavaScript
- Продвинутый JavaScript
- Node.js и серверный JavaScript
- TypeScript
- DOM API и работа с браузером
- NPM - менеджер пакетов
- Архитектура и внутреннее устройство
JavaScript (1995):
- Создан Бренданом Эйхом за 10 дней для Netscape Navigator
- Изначально назывался Mocha → LiveScript → JavaScript (маркетинговый ход)
- ECMAScript 1 (1997) - первая стандартизация
- Заморозка развития (1999-2009) из-за "войны браузеров"
Node.js (2009):
- Создан Райаном Далем
- Решение проблемы блокирующего I/O
- Объединил V8, event loop и модульную систему
TypeScript (2012):
- Создан Андерсом Хейлсбергом (Turbo Pascal, Delphi, C#)
- Решение проблемы масштабирования больших проектов
JavaScript:
- Простота поверх сложности (сложные механизмы скрыты)
- Прототипное наследование (классы - синтаксический сахар)
- Функции как граждане первого класса
- Неблокирующая природа (event-driven)
Node.js:
- Один поток на соединение (неблокирующий I/O)
- Модульность (маленькие компоненты)
- Потоковая обработка данных
- Обработка ошибок first-callback
TypeScript:
- Статическая типизация как документация
- Постепенное внедрение (совместимость с JS)
- Структурная типизация (duck typing)
- Типы как дизайн (сначала типы, потом реализация)
// Объявление
let переменная = значение; // Может изменяться
const константа = значение; // Неизменяемая
var устаревшая = значение; // Устарело (function scope)
// Типы данных
const строка = "Текст";
const число = 42;
const булево = true;
const ничто = null;
const неопределено = undefined;
const символ = Symbol('id');
const большоеЧисло = 123n; // BigInt
const объект = { ключ: "значение" };
const массив = [1, 2, 3];// Арифметические
+ - * / % **
// Сравнения
== // Нестрогое (приводит типы)
=== // Строгое (тип + значение)
!= !== > < >= <=
// Логические
&& // И (возвращает первое ложное или последнее)
|| // ИЛИ (возвращает первое истинное или последнее)
! // НЕ// Условные
if (условие) { }
else if (условие) { }
else { }
// Тернарный оператор
условие ? значение1 : значение2;
// Switch
switch(значение) {
case вариант1: код; break;
default: код;
}
// Циклы
for (инициализация; условие; шаг) { }
while (условие) { }
do { } while (условие);
// Итерация
for (элемент of массив) { } // Значения
for (ключ in объект) { } // Ключи// Объявление
function имя(параметры) { return значение; }
// Функциональное выражение
const функция = function(параметры) { };
// Стрелочные функции
const стрелка = (параметры) => выражение;
const безСкобок = параметр => выражение;
const безПараметров = () => выражение;
// Особенности
function соЗначениемПоУмолчанию(параметр = "дефолт") { }
function соМножествомАргументов(...аргументы) { }
function сДеструктуризацией({свойство1, свойство2}) { }const массив = [1, 2, 3, 4, 5];
// Мутирующие методы
массив.push(элемент); // Добавить в конец
массив.pop(); // Удалить с конца
массив.unshift(элемент); // Добавить в начало
массив.shift(); // Удалить с начала
массив.splice(индекс, количество, элементы); // Удалить/вставить
// Неизменяющие методы
массив.map(функция); // Трансформировать
массив.filter(функция); // Отфильтровать
массив.reduce(функция, начальноеЗначение); // Аккумулировать
массив.forEach(функция); // Итерация
массив.find(функция); // Найти элемент
массив.findIndex(функция); // Найти индекс
массив.some(функция); // Хотя бы один
массив.every(функция); // Все
массив.includes(значение); // Проверить наличиеconst объект = {
свойство: "значение",
метод() { return this.свойство; }
};
// Доступ
объект.свойство; // Точечная нотация
объект["свойство"]; // Скобочная нотация
// Модификация
объект.новоеСвойство = "значение";
delete объект.свойство;
// Проверка
"свойство" in объект;
объект.hasOwnProperty("свойство");
// Деструктуризация
const { свойство1, свойство2 } = объект;
// Spread/Rest
const новыйОбъект = { ...старый, новое: "значение" };
// Методы Object
Object.keys(объект); // Массив ключей
Object.values(объект); // Массив значений
Object.entries(объект); // Массив пар [ключ, значение]function внешняя() {
let секретная = "переменная"; // Локальная переменная
return function внутренняя() {
// Имеет доступ к секретной даже после завершения внешней
return секретная;
};
}
const получитьСекрет = внешняя();
console.log(получитьСекрет()); // "переменная"// В обычной функции - зависит от вызова
function обычная() {
console.log(this); // window (в нестрогом режиме)
}
// В стрелочной - берется из внешней области
const стрелочная = () => {
console.log(this); // window (как в момент создания)
};
// Методы объекта
const объект = {
значение: "объект",
обычныйМетод: function() { console.log(this.значение); }, // "объект"
стрелочныйМетод: () => { console.log(this.значение); } // undefined
};
// Явная привязка
обычная.call(контекст, аргументы); // Применить контекст
обычная.apply(контекст, [аргументы]); // Применить контекст (массив)
const привязанная = обычная.bind(контекст); // Создать новую функцию// Конструктор
function Животное(имя) {
this.имя = имя;
}
// Методы в прототипе
Животное.prototype.говорить = function() {
console.log(`${this.имя} издает звук`);
};
// Наследование
function Собака(имя, порода) {
Животное.call(this, имя); // Вызов родительского конструктора
this.порода = порода;
}
// Цепочка прототипов
Собака.prototype = Object.create(Животное.prototype);
Собака.prototype.constructor = Собака;
// Метод потомка
Собака.prototype.лаять = function() {
console.log(`${this.имя} лает`);
};class Животное {
constructor(имя) {
this.имя = имя;
}
// Метод экземпляра
говорить() {
console.log(`${this.имя} издает звук`);
}
// Статический метод
static являетсяЖивотным(объект) {
return объект instanceof Животное;
}
// Приватное поле (ES2022)
#секрет = "секрет";
// Геттер/сеттер
set возраст(значение) {
if (значение > 0) this._возраст = значение;
}
get возраст() {
return this._возраст;
}
}
class Собака extends Животное {
constructor(имя, порода) {
super(имя); // Вызов родительского конструктора
this.порода = порода;
}
// Переопределение метода
говорить() {
super.говорить(); // Вызов родительского метода
console.log(`${this.имя} лает`);
}
}// Создание промиса
const промис = new Promise((разрешить, отклонить) => {
// Асинхронная операция
успех ? разрешить(результат) : отклонить(ошибка);
});
// Обработка
промис
.then(результат => { /* обработка успеха */ })
.catch(ошибка => { /* обработка ошибки */ })
.finally(() => { /* выполнится всегда */ });
// Async/await
async function асинхроннаяФункция() {
try {
const результат = await промис;
return результат;
} catch (ошибка) {
throw ошибка;
}
}
// Методы Promise
Promise.all([промисы]); // Ждет все
Promise.race([промисы]); // Ждет первый
Promise.allSettled([промисы]); // Ждет завершения всех
Promise.any([промисы]); // Первый успешный// export.js
export const константа = значение;
export function функция() { }
export default класс { }
// import.js
import КлассПоУмолчанию, { константа, функция } from './export.js';
import * как Имя from './export.js'; // Импорт всего
// Динамический импорт
const модуль = await import('./module.js');const fs = require('fs');
const fsPromises = require('fs').promises;
// Синхронные операции
const данные = fs.readFileSync('файл.txt', 'utf8');
// Асинхронные с коллбэком
fs.readFile('файл.txt', 'utf8', (ошибка, данные) => {
if (ошибка) throw ошибка;
console.log(данные);
});
// Promise-based
async function прочитатьФайл() {
const данные = await fsPromises.readFile('файл.txt', 'utf8');
return данные;
}
// Пути
const path = require('path');
path.join(__dirname, 'папка', 'файл.txt'); // Абсолютный путь
path.resolve('папка', 'файл.txt'); // Разрешение путиconst http = require('http');
const сервер = http.createServer((запрос, ответ) => {
// Заголовки ответа
ответ.writeHead(200, {
'Content-Type': 'text/html'
});
// Тело ответа
ответ.write('<h1>Привет</h1>');
// Завершение
ответ.end();
});
сервер.listen(3000, () => {
console.log('Сервер запущен на порту 3000');
});const express = require('express');
const приложение = express();
// Middleware
приложение.use(express.json()); // Парсинг JSON
// Маршруты
приложение.get('/', (запрос, ответ) => {
ответ.send('Главная страница');
});
приложение.get('/пользователи/:ид', (запрос, ответ) => {
const идПользователя = запрос.params.ид;
ответ.json({ ид: идПользователя });
});
приложение.post('/пользователи', (запрос, ответ) => {
const данныеПользователя = запрос.body;
ответ.status(201).json({ сообщение: 'Создан' });
});
// Middleware ошибок
приложение.use((ошибка, запрос, ответ, далее) => {
console.error(ошибка.stack);
ответ.status(500).send('Ошибка сервера');
});
приложение.listen(3000);const mongoose = require('mongoose');
// Подключение
mongoose.connect('mongodb://localhost/базаданных');
// Схема
const схемаПользователя = new mongoose.Schema({
имя: String,
email: { type: String, required: true }
});
// Модель
const Пользователь = mongoose.model('Пользователь', схемаПользователя);
// CRUD операции
const новыйПользователь = new Пользователь({ имя: 'Иван' });
новыйПользователь.save(); // Создание
Пользователь.find({}); // Чтение всех
Пользователь.findByIdAndUpdate(ид, обновления); // Обновление
Пользователь.findByIdAndDelete(ид); // Удаление// Сервер
const сервер = require('http').createServer();
const io = require('socket.io')(сервер);
io.on('connection', (сокет) => {
console.log('Новый клиент подключен');
сокет.on('сообщение', (данные) => {
io.emit('сообщение', данные); // Всем клиентам
});
сокет.on('disconnect', () => {
console.log('Клиент отключен');
});
});
// Клиент (браузер)
<script src="/socket.io/socket.io.js"></script>
<script>
const сокет = io();
сокет.emit('сообщение', 'Привет');
сокет.on('сообщение', (данные) => {
console.log('От сервера:', данные);
});
</script>let логическое: boolean = true;
let число: number = 42;
let строка: string = "текст";
// Массивы
let массивЧисел: number[] = [1, 2, 3];
let другойМассив: Array<number> = [1, 2, 3];
// Tuple
let кортеж: [string, number] = ["привет", 10];
// Enum
enum Цвет { Красный, Зеленый, Синий }
let цвет: Цвет = Цвет.Зеленый;
// Any (избегайте)
let чтоУгодно: any = 4;
чтоУгодно = "строка";
// Void
function предупредить(): void {
console.log("Предупреждение");
}
// Never
function ошибка(сообщение: string): never {
throw new Error(сообщение);
}// Интерфейс
interface Пользователь {
ид: number;
имя: string;
возраст?: number; // Необязательный
readonly email: string; // Только чтение
}
// Использование
const пользователь: Пользователь = {
ид: 1,
имя: "Иван",
email: "[email protected]"
};
// Расширение
interface Админ extends Пользователь {
разрешения: string[];
}
// Type Aliases
type Точка = {
x: number;
y: number;
};
type Идентификатор = number | string;
// Generics
interface Коробка<T> {
значение: T;
}
const коробкаСЧислом: Коробка<number> = { значение: 42 };class Животное {
// Модификаторы доступа
public имя: string; // Доступ везде
private секрет: string; // Только внутри класса
protected возраст: number; // Класс и наследники
// Статические
static количество: number = 0;
constructor(имя: string) {
this.имя = имя;
Животное.количество++;
}
// Абстрактный метод
abstract издатьЗвук(): void;
}
class Собака extends Животное {
порода: string;
constructor(имя: string, порода: string) {
super(имя);
this.порода = порода;
}
издатьЗвук(): void {
console.log("Гав!");
}
}{
"compilerOptions": {
"target": "ES2020", // Целевая версия ECMAScript
"module": "commonjs", // Система модулей
"lib": ["ES2020"], // Используемые библиотеки
"outDir": "./dist", // Директория вывода
"rootDir": "./src", // Директория исходников
"strict": true, // Строгий режим
"esModuleInterop": true, // Совместимость модулей
"skipLibCheck": true, // Пропуск проверки библиотек
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}// По ID
const элемент = document.getElementById('ид');
// По CSS селектору
const первый = document.querySelector('.класс');
const все = document.querySelectorAll('.класс');
// Устаревшие методы
const поКлассу = document.getElementsByClassName('класс'); // HTMLCollection
const поТегу = document.getElementsByTagName('div'); // HTMLCollection
const поИмени = document.getElementsByName('имя'); // NodeList// Содержимое
элемент.innerHTML; // HTML (опасно!)
элемент.textContent; // Текст (безопасно)
элемент.innerText; // Видимый текст
// Навигация
элемент.parentElement; // Родительский элемент
элемент.children; // Дочерние элементы
элемент.firstElementChild; // Первый дочерний элемент
элемент.previousElementSibling; // Предыдущий сосед
элемент.nextElementSibling; // Следующий сосед
// Изменение
элемент.textContent = 'новый текст';
элемент.innerHTML = '<span>HTML</span>'; // Осторожно!
// Вставка
родитель.appendChild(элемент); // В конец
родитель.prepend(элемент); // В начало
элемент.before(новыйЭлемент); // Перед элементом
элемент.after(новыйЭлемент); // После элемента
элемент.replaceWith(новыйЭлемент); // Заменить
// Удаление
элемент.remove();// Стандартные атрибуты
элемент.id = 'новый-ид';
элемент.className = 'класс1 класс2';
// Универсальные методы
элемент.getAttribute('data-ид');
элемент.setAttribute('data-ид', 'значение');
элемент.hasAttribute('data-ид');
элемент.removeAttribute('data-ид');
// data-* атрибуты
элемент.dataset.ид = '123'; // Становится data-id="123"
// classList
элемент.classList.add('новый-класс');
элемент.classList.remove('старый-класс');
элемент.classList.toggle('активный');
элемент.classList.contains('активный');
элемент.classList.replace('старый', 'новый');// Добавление обработчика
элемент.addEventListener('клик', (событие) => {
console.log(событие.type); // 'click'
console.log(событие.target); // Целевой элемент
console.log(событие.currentTarget); // Элемент с обработчиком
событие.preventDefault(); // Отменить действие по умолчанию
событие.stopPropagation(); // Остановить всплытие
});
// Удаление
элемент.removeEventListener('клик', обработчик);
// Делегирование событий
родитель.addEventListener('клик', (событие) => {
if (событие.target.classList.contains('дочерний')) {
// Обработка клика на дочернем элементе
}
});
// Основные типы событий
'click', 'dblclick', 'mousedown', 'mouseup', 'mousemove'
'keydown', 'keyup', 'keypress'
'submit', 'change', 'input', 'focus', 'blur'
'load', 'DOMContentLoaded', 'resize', 'scroll'// Inline стили
элемент.style.color = 'red';
элемент.style.fontSize = '16px';
// Вычисленные стили
const стили = window.getComputedStyle(элемент);
const цвет = стили.color;
// CSS классы (рекомендуется)
элемент.classList.add('активный');
// CSS переменные
элемент.style.setProperty('--цвет', '#ff0000');
// Позиция и размеры
const rect = элемент.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);// CSS анимации
элемент.style.transition = 'all 0.3s ease';
элемент.style.transform = 'translateX(100px)';
// Web Animations API
const анимация = элемент.animate(
[
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(1.5)', opacity: 0.5 }
],
{
duration: 1000,
iterations: Infinity,
direction: 'alternate'
}
);
// requestAnimationFrame для кастомных анимаций
function анимировать() {
элемент.style.left = (left + 1) + 'px';
requestAnimationFrame(анимировать);
}
requestAnimationFrame(анимировать);# Инициализация проекта
npm init # Интерактивно
npm init -y # Автоматически
# Установка пакетов
npm install пакет # В dependencies
npm install пакет --save-dev # В devDependencies
npm install пакет --save-optional # В optionalDependencies
npm install пакет -g # Глобально
# Версии
npm install пакет@1.2.3 # Конкретная версия
npm install пакет@latest # Последняя версия
npm install пакет@next # Следующая версия
# Обновление
npm update # Обновить все
npm update пакет # Обновить пакет
npm outdated # Проверить устаревшие
# Удаление
npm uninstall пакет
npm remove пакет
# Информация
npm list # Установленные пакеты
npm view пакет # Информация о пакете
npm search ключевые_слова # Поиск пакетов
npm docs пакет # Документация{
"name": "имя-пакета",
"version": "1.0.0",
"description": "Описание",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "jest",
"build": "webpack",
"dev": "nodemon index.js"
},
"keywords": ["ключевые", "слова"],
"author": "Автор",
"license": "MIT",
"dependencies": {
"express": "^4.18.0",
"lodash": "4.17.21"
},
"devDependencies": {
"jest": "^28.0.0",
"webpack": "^5.0.0"
},
"peerDependencies": {
"react": ">=16.0.0"
},
"engines": {
"node": ">=14.0.0",
"npm": ">=7.0.0"
},
"files": ["dist/", "src/"],
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}{
"scripts": {
// Предопределенные скрипты
"prepublish": "npm run build",
"prepare": "npm run build",
"prepublishOnly": "npm test",
"postinstall": "node postinstall.js",
// Пользовательские
"dev": "nodemon server.js",
"build": "webpack --mode production",
"test": "jest",
"lint": "eslint src/",
"clean": "rimraf dist/",
// Параллельное выполнение
"dev:all": "npm-run-all --parallel dev:*",
"dev:server": "nodemon server.js",
"dev:client": "webpack-dev-server",
// С хуками
"prebuild": "echo 'Начинаем сборку'",
"postbuild": "echo 'Сборка завершена'"
}
}# Проверка уязвимостей
npm audit
npm audit fix # Автоматическое исправление
npm audit fix --force # Принудительное исправление
# Двухфакторная аутентификация
npm profile enable-2fa auth-and-writes
npm publish --otp=123456
# Проверка владельцев
npm owner ls пакет{
"name": "монорепозиторий",
"private": true,
"workspaces": ["packages/*", "apps/*"]
}# Работа с workspaces
npm install --workspace=пакеты/ui
npm run build --workspaces
npm publish --workspace=пакеты/uiИсходный код → Парсер → AST → Интерпретатор (Ignition) → Байткод
↓
Сбор информации
↓
Компилятор (TurboFan) → Машинный код
Компоненты V8:
- Parser - преобразует код в AST
- Ignition - интерпретатор байткода
- TurboFan - оптимизирующий компилятор
- Orinoco - сборщик мусора
Фазы Event Loop:
1. Timers (setTimeout, setInterval)
2. Pending callbacks (системные операции)
3. Idle, prepare (внутренние операции)
4. Poll (новые I/O события)
5. Check (setImmediate)
6. Close callbacks (закрытие соединений)
Микрозадачи vs Макрозадачи:
- Микрозадачи: Promise, process.nextTick, queueMicrotask
- Макрозадачи: setTimeout, setInterval, setImmediate, I/O
- Порядок: Микрозадачи → Макрозадачи
Heap (куча) разделяется на:
- New Space (Young Generation) - кратковременные объекты (Scavenge алгоритм)
- Old Space (Old Generation) - долгоживущие объекты (Mark-Sweep-Compact)
- Large Object Space - большие объекты
- Code Space - скомпилированный код
CommonJS (Node.js):
// module.js
module.exports = { };
exports.функция = function() { };
// main.js
const модуль = require('./module.js');ES Modules:
// module.js
export const значение = 42;
export default function() { };
// main.js
import функцияПоУмолчанию, { значение } from './module.js';const fs = require('fs');
const { Readable, Writable, Transform } = require('stream');
// Чтение
const читаемый = fs.createReadStream('вход.txt');
// Запись
const записываемый = fs.createWriteStream('выход.txt');
// Конвейер
читаемый.pipe(записываемый);
// Кастомный поток
class ВерхнийРегистр extends Transform {
_transform(чанк, кодировка, коллбэк) {
this.push(чанк.toString().toUpperCase());
коллбэк();
}
}Основные уязвимости:
- Injection attacks - параметризованные запросы
- XSS - экранирование пользовательского ввода
- CSRF - токены
- Небезопасные зависимости - регулярные обновления
Лучшие практики кода:
// 1. Используйте const
const КОНСТАНТА = значение;
// 2. Деструктуризация
const { свойство1, свойство2 } = объект;
// 3. Опциональная цепочка
const улица = пользователь?.адрес?.улица;
// 4. Нулевое слияние
const значение = ввод ?? 'значение по умолчанию';
// 5. async/await с обработкой ошибок
async function получитьДанные() {
try {
const данные = await асинхроннаяОперация();
return данные;
} catch (ошибка) {
console.error(ошибка);
throw ошибка;
}
}
// 6. Валидация входных данных
function валидироватьПользователя(пользователь) {
if (!пользователь.имя || !пользователь.email) {
throw new Error('Неверные данные пользователя');
}
}Оптимизация DOM:
// ПЛОХО: Множественные чтения/записи
for (let i = 0; i < 100; i++) {
const ширина = элемент.offsetWidth; // Чтение (reflow)
элемент.style.width = (ширина + 10) + 'px'; // Запись (reflow)
}
// ХОРОШО: Группировка операций
const ширина = элемент.offsetWidth; // Одно чтение
const новыеСтили = [];
for (let i = 0; i < 100; i++) {
новыеСтили.push(`${ширина + i * 10}px`);
}
элемент.style.width = новыеСтили[99]; // Одна запись
// ЛУЧШЕ: requestAnimationFrame
function обновитьШирину() {
const ширина = элемент.offsetWidth;
элемент.style.width = (ширина + 10) + 'px';
if (ширина < 1000) {
requestAnimationFrame(обновитьШирину);
}
}Оптимизация npm:
# Чистая установка для CI/CD
npm ci # вместо npm install
# Пропуск необязательных зависимостей
npm install --no-optional
# Только production зависимости
npm install --production
# Анализ размера
npx bundle-phobia lodashJavaScript:
- Динамическая типизация и прототипное наследование
- Event Loop и неблокирующая модель
- Функции как объекты первого класса
Node.js:
- Однопоточный event-driven архитектура
- Неблокирующий I/O через libuv
- Модульная система CommonJS/ESM
TypeScript:
- Статическая типизация поверх JavaScript
- Структурная типизация (duck typing)
- Инструменты для масштабирования проектов
- npm - менеджер пакетов и экосистема
- DOM API - взаимодействие с браузером
- DevTools - отладка и профилирование
- Bundlers - Webpack, Rollup, Vite
- Testing - Jest, Mocha, Cypress