286 lines
12 KiB
Markdown
286 lines
12 KiB
Markdown
- Встраиваемый расширяемый не имеющий средств ввода-вывода ЯП
|
||
- 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<String, Object>` джавы
|
||
- Массивы, функции, даты, регулярки - все это `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$ повтор цикла. |