- Встраиваемый расширяемый не имеющий средств ввода-вывода ЯП - 5 примитивных типов данных - Number, String, Boolean, Null, Undefined - Объектный тип данных - Object - 15 различных видов инструкций > [!warning] Дальнейшие примеры будут до стандарта ES6, то есть не совсем актуальные, использование `var` - моветон в наше время. Также после 2020 года уже 7 примитивов - еще Symbol и BigInt ## Особенности языка - Блок не ограничивает область видимости переменной: ```JavaScript function foo() { var sum = 0; for (var i = 0; i < 42; i += 2) { var tmp = i+2; sum += i*tmp; } for (var i = 1; i < 42; i += 2) { sum += i*i; } alert(tmp); // вне зоны return sum; } foo(); ``` - Если переменная объявлена вне функции, то она в глобальной области видимости ```JavaScript var a = 42; function foo() { alert(a); } foo(); ``` > [!hint] `alert()` вызывает всплывающее окно, синхронный и блокирующий метод - блокирует Event Loop - Функция - это тоже объект ```JavaScript function sum(a, b) { return a+b; } var sum2 = function(a, b) { return a+b; } var sum3 = new Function("a", "b", "return a+b;"); // без комментариев ``` ## ES6 - Новая версия, выпущенная в 2015 году - Добавляет новый синтаксис > [!warning] Дальше примеры для ES6 и новее ## let и const Два новых ключевых слова `let` - переменная с областью видимости в блоке `const` - константа ## Форматирование вывода ```JavaScript const first = 'Adrian'; const last = 'Mejia'; console.log(`Your name is ${first} ${last}.`); ``` > [!hint] Нужны косые кавычки `` ## Деструктуризация - Особый синтаксис присваивания, при котором можно присвоить массив или объект сразу нескольким переменным, разбив его на части ```JavaScript const array = [1, 2, 3, 4]; const [first, ,third] = array; console.log(first, third); // 1 3 ``` - Обмен значениями ```JavaScript let a = 1; let b = 2; [a, b] = [b, a]; console.log(a, b); // 2 1 ``` - Сопоставление параметров ```JavaScript const user = {firstName: 'Adrian', lastName: 'Mejia'}; function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; } console.log(getFullName(user)); // Adrian Mejia ``` > [!hint] { } - создание объекта, аналог хэш-мапы - Деструктуризация объекта ```JavaScript function settings() { return { display: { color: 'red' }, keyboard: { layout: 'querty' } }; } const { display: { color: displayColor }, keyboard: { layout: keyboardLayout }} = settings(); console.log(displayColor, keyboardLayout); // red querty ``` > [!hint] {} до знака равно - распаковка объектов, а не их создание ## Классы и объекты ```JavaScript class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } const animal = new Animal('animal'); animal.speak(); // animal makes a noise. ``` ## Наследование ```JavaScript class Lion extends Animal { speak() { super.speak(); console.log(this.name + ' roars.'); } } const lion = new Lion('Simba'); lion.speak(); // Simba makes a noise. // Simba roars. ``` ## Типы данных #### `Number` - Любое число под капотом это 64-битное число с плавающей точкой (как `double` в джаве). - `Infinity / -Infinity` (например при делении на 0) - `NaN` (например при делении строки на число) - Опасность сравнения `0.1 + 0.2 === 0.3 // false` #### `String` - В `UTF-16` - Нет разницы между одинарными и двойными кавычками #### `Boolean` - `true` / `false` #### `Undefined` - `undefined` - Техническое значение по умолчанию - Присваивает сам движок #### `Null` - `null` - Намеренное отсутствие значения #### `Symbol` - Уникальный и неизменяемый идентификатор - `Symbol("id") === Symbol("id") // false` - Нужен для создания скрытых свойств внутри объектов, которые нельзя случайно перезаписать или увидеть при обычном переборе через `for...in` #### `Object` - Все, что не примитив - Например словари `{}` - аналог `HashMap` джавы - Массивы, функции, даты, регулярки - все это `Object` ## Приведение типов Существует два оператора равенства: `==` и `===` #### Строгое равенство `===` - Проверяет и тип, и значение - Никаких скрытых преобразований ```JavaScript 5 === 5 // true 5 === "5" // false 0 === "false" // false null === undefined // false ``` #### Нестрогое равенство `==` - Оператор с неявным приведением типов. Если типы разные, движок пытается привести их к одному (чаще всего к числу) по алгоритму ##### Правила кастов 1. Каста `null` и `undefined` - они равны друг другу, но больше не равны ничему в языке ```JavaScript null == undefined // true null == 0 // false ``` 2. Булеан -> Число (в 0 или 1) 3. Строка -> Число (`"5" -> 5`, `"" -> 0`, `"hello" -> NaN`) 4. Объект -> Примитив (через метод `.toString`) ## Стрелочные функции ```JavaScript $('.btn').click((event) => this.sendData()); ``` ## Цикл с итератором ```JavaScript var array = ['a', 'b']; for (var i = 0; i < array.length; i++) { var el = array[i]; console.log(el); } array.forEach(function (el) { console.log(el) }); array.forEach((el) => console.log(el)); for (const el of array) { console.log(el); } ``` ## Параметры по умолчанию ```JavaScript function point(x=0, y=-1, isFlag=true) { ... } ``` ## Rest-параметры Типо `vararg` в джаве ```JavaScript function printf(format, ...params) { ... } ``` ### Операция spread ```JavaScript Math.max(...[2,100,1,6,43]); const array1 = [1,2,3]; const array2 = ['a', 'b']; const array3 = [false, true]; console.log([...array1, ...array2, ...array3]) ``` ## Promise Это специальный объект, который представляет собой результат асинхронной операции JavaScript - однопоточный, используется Event Loop в одном потоке До промисов был ад колбэков ```JavaScript // Старый ад (Pyramid of Doom): getUser(userId, function(user) { getOrders(user.id, function(orders) { getOrderDetails(orders[0].id, function(details) { // И так до бесконечности вправо... }); }); }); ``` #### Состояния промиса 1. `pending` (ожидание) - операция запущена, но еще не завершилась 2. `fulfilled` (выполнено усешно) - вернул результат 3. `rejected` (отклонено с ошибкой) - произошла ошибка #### Работа с промисом `.then()`, `.catch()`, `.finally()` ```JavaScript fetch("https://api.com/user/1") // отправка запроса .then(response => response.json()) .then(user => { console.log(user.name); }) .catch(error => { // ошибка на любом этапе console.error(error); }) .finally(() => { // выполнится всегда console.log('Done'); }) ``` Свой промис ```JavaScript function printAfterTimeout(string, timeout) { return new Promise((resolve, reject) => { setTimeout(function(){ resolve(string); }, timeout); }); } printAfterTimeout('Hello', 2e3) .then((result) => { console.log(result); return printAfterTimeout(result + 'Reader', 2e3); }).then((result) => { console.log(result); }); ``` > [!hint] В новый промис передается две функции `resolve` - при успехе и `reject` - при ошибке #### Async и Await Появились в `ES8` (2017 год). Способ писать асинхронный код так, чтобы он читался как синхронный Замена цепочкам `.then().catch()` - `async` пишется перед объявлением функции. Такая функция автоматически оборачивает то, что возвращает, в `Promise` - Ключевое слово `await` заставляет функцию поставить выполнение на паузу и дождаться результата - `await` можено использовать только внутри `async` функций ```JavaScript async function loadUser() { try { const response = await fetch("https://api.com/..."); const user = await response.json(); console.log(user); } catch (error) { console.error(error) } } ``` ## Event Loop и Асинхронность JavaScript в браузере (и Node.js) — **строго однопоточный язык**. У него есть только один **Call Stack (Стек вызовов)**, который может выполнять только одну операцию одновременно. Чтобы не блокировать поток тяжелыми задачами (запросы в сеть, таймеры), JS использует механизм **Event Loop (Цикл событий)** и делегирует работу фоновым C++ потокам браузера (Web APIs). #### Приоритет выполнения задач Движок JS распределяет код и колбэки по трем уровням приоритета: 1. **Стек вызовов (Call Stack) — Абсолютный приоритет** Весь текущий синхронный код (циклы `for`, обычные функции, `console.log`). Действует правило *Run-to-completion*: пока стек не опустеет полностью, никакие асинхронные задачи из очередей не начнут выполняться, даже если они уже готовы. Блокировка стека (например, `while(true)`) намертво вешает весь браузер. 2. **VIP-очередь (Микротаски / Microtasks) — Высокий приоритет** Сюда попадают колбэки от **Промисов** (`.then()`, `catch()`, код после `await`) и `MutationObserver`. Как только Стек пустеет, Event Loop берет микротаски и выполняет их **все до единой**, пока эта очередь не станет абсолютно пустой. 3. **Обычная очередь (Макротаски / Macrotasks) — Низкий приоритет** Сюда попадают **Таймеры** (`setTimeout`, `setInterval`) и **события пользователя** (клики `click`, ввод с клавиатуры). Из этой очереди Event Loop берет строго **по ОДНОЙ** задаче за один цикл. Выполнив одну макрозадачу, он снова бежит проверять, не появились ли новые микротаски (Промисы), и только потом берет следующую макрозадачу. > [!hint] Кратко: порядок выполнения > Синхронный СТЕК $\to$ ВСЕ Микротаски (Промисы) $\to$ ОДНА Макротаска (Таймеры) $\to$ повтор цикла.