https://github.com/sa2kasov/javascript-reference-guide
Reference Guide of JavaScript, DOM, BOM
https://github.com/sa2kasov/javascript-reference-guide
bom dom javascript javascript-guide javascript-references
Last synced: 29 days ago
JSON representation
Reference Guide of JavaScript, DOM, BOM
- Host: GitHub
- URL: https://github.com/sa2kasov/javascript-reference-guide
- Owner: sa2kasov
- License: mit
- Created: 2024-01-21T03:07:39.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-04-13T14:04:48.000Z (about 2 years ago)
- Last Synced: 2024-04-14T16:22:05.106Z (about 2 years ago)
- Topics: bom, dom, javascript, javascript-guide, javascript-references
- Homepage:
- Size: 99.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# JavaScript: Справочное руководство
### Содержание
1. [История появления](#история-появления)
1. [Создатель языка о его происхождении](#создатель-языка-о-его-происхождении)
2. [Введение в JavaScript](#введение-в-javascript)
3. [Комментарии](#комментарии)
4. [JavaScript в HTML](#javascript-в-html)
5. [Переменные](#переменные)
1. [let](#let)
2. [const](#const)
3. [var](#var)
6. [Операторы](#операторы)
1. [Арифметические](#арифметические-операторы)
2. [Операторы сравнения](#операторы-сравнения)
3. [Логические операторы](#логические-операторы)
7. [Выражения и инструкции](#выражения-и-инструкции)
8. [Типы данных](#типы-данных)
1. [Логический тип](#логический-тип)
2. [Числа](#числа)
3. [Строки](#строки)
1. [Экранирование символов](#экранирование-символов)
2. [Конкатенация](#конкатенация)
3. [Сравнение строк](#сравнение-строк)
4. [Шаблонные литералы](#шаблонные-литералы)
4. [Манипуляции с типами](#манипуляции-с-типами)
5. [Приведение типов](#приведение-типов)
1. [Таблица преобразования типов](#таблица-преобразования-типов)
9. [Управляющие конструкции](#управляющие-конструкции)
1. [if](#if)
2. [Тернарный оператор](#тернарный-оператор)
3. [switch](#switch)
4. [for](#for)
5. [while](#while)
6. [do..while](#dowhile)
7. [for..in](#forin)
8. [Метки](#Метки)
9. [try..catch..finally](#trycatchfinally)
10. [Функции](#функции)
1. [Области видимости](#области-видимости)
2. [Функция как тип данных](#функция-как-тип-данных)
3. [Свойства функций](#свойства-функций)
4. [Анонимная функция](#анонимная-функция)
5. [Стрелочные функции](#стрелочные-функции)
6. [Замыкания](#замыкания)
7. [Рекурсия](#рекурсия)
7. [Поднятие (Hoisting)](#поднятие-hoisting)
11. [Объекты](#объекты)
1. [Создание объекта](#создание-объекта)
2. [Свойства объекта](#свойства-объекта)
1. [Работа свойствами объекта](#работа-свойствами-объекта)
2. [Перебор свойств объекта](#перебор-свойств-объекта)
3. [Сравнение объектов](#сравнение-объектов)
4. [Создание методов в объекте](#создание-методов-в-объекте)
5. [Методы объекта Object](#методы-объекта-object)
1. [Доступ к свойствам объекта](#доступ-к-свойствам-объекта)
2. [Управление свойствами объекта](#управление-свойствами-объекта)
3. [Прочие методы объекта](#прочие-методы-объекта)
6. [Создание метода из имеющейся функции](#создание-метода-из-имеющейся-функции)
7. [call / apply](#call--apply)
12. [Массивы](#массивы)
1. [Создание и работа с массивами](#создание-и-работа-с-массивами)
2. [Добавление элементов в созданный массив](#добавление-элементов-в-созданный-массив)
3. [Перебор элементов массива](#перебор-элементов-массива)
4. [Удаление элемента массива](#удаление-элемента-массива)
5. [Методы для работы с массивами](#методы-для-работы-с-массивами)
1. [Создание массивов](#создание-массивов)
2. [Доступ к элементам массива](#доступ-к-элементам-массива)
3. [Поиск элементов массива](#поиск-элементов-массива)
4. [Получение строки из массива](#получение-строки-из-массива)
5. [Конкатенация массивов](#конкатенация-массивов)
6. [Получение части массива](#получение-части-массива)
7. [Вставка и удаление в любом месте](#вставка-и-удаление-в-любом-месте)
8. [Сортировка массива](#сортировка-массива)
9. [Работа с началом массива](#работа-с-началом-массива)
10. [Работа с концом массива](#работа-с-концом-массива)
11. [Поиск элементов массива](#поиск-элементов-массива)
12. [Итерация по элементам массива](#итерация-по-элементам-массива)
13. [Сведение массива к одному значению](#сведение-массива-к-одному-значению)
14. [Преобразование массива](#преобразование-массива)
15. [Другие методы массива](#другие-методы-массива)
13. [Встроенные объекты](#встроенные-объекты)
1. [Глобальный объект](#глобальный-объект)
1. [Глобальные свойства](#глобальные-свойства)
2. [Глобальные методы](#глобальные-методы)
3. [Примеры использования](#примеры-использования)
2. [Number](#number)
1. [Свойства](#свойства-number)
2. [Методы](#методы-number)
3. [String](#string)
1. [Свойства](#свойства-string)
2. [Методы](#методы-string)
3. [Примеры](#примеры-string)
4. [Math](#math)
1. [Свойства](#свойства-math)
2. [Методы](#методы-math)
5. [Date](#date)
1. [Создание даты](#создание-даты)
2. [Методы](#методы-date)
6. [RegExp: Регулярные выражения](#регулярные-выражения)
1. [Создание](#создание-regexp)
2. [Специальные последовательности](#специальные-последовательности)
3. [Позиции соответствия](#позиции-соответствия)
4. [Операторы регулярного выражения](#операторы-регулярного-выражения)
5. [Квантификаторы](#квантификаторы)
6. [Методы регулярного выражения](#методы-регулярного-выражения)
7. [Примеры использования](#примеры-regex)
7. [Error](#error)
1. [Инициирование исключения](#инициирование-исключения)
14. [Объектно-ориентированное программирование](#объектно-ориентированное-программирование)
1. [Принципы ООП](#принципы-ооп)
2. [Функция-конструктор](#функция-конструктор)
3. [Прототипы](#прототипы)
4. [Классы](#классы)
15. [BOM (Объектная модель браузера)](#bom-Объектная-модель-браузера)
1. [Свойства и методы объекта Window](#свойства-и-методы-window)
2. [Фреймы](#фреймы)
1. [Работа с окнами](#работа-с-окнами)
3. [navigator](#navigator)
4. [history](#history)
5. [location](#location)
6. [screen](#screen)
16. [Клиентский JavaScript](#клиентский-javascript)
1. [Управление загрузкой скриптов. Атрибуты aync и defer](#управление-загрузкой-скриптов.-атрибуты-aync-и-defer)
17. [DOM (Объектная модель документа)](#dom-объектная-модель-документа)
1. [Свойства](#свойства-document)
2. [Методы](#методы-document)
3. [Типы узлов документа](#типы-узлов-документа)
4. [Связи между DOM-элементами](#связи-между-dom-элементами)
5. [Свойства и методы типов узлов DOM](#свойства-и-методы-типов-узлов-dom)
1. [Node](#node)
2. [Element](#element)
3. [HTMLElement](#htmlelement)
4. [Document](#document)
5. [Примеры свойств и методов](#примеры-свойств-и-методов-узлов-dom)
18. [События](#события)
1. [Обработчики событий](#обработчики-событий)
2. [Объект события](#объект-события)
3. [Отмена действия по умолчанию](#отмена-действия-по-умолчанию)
4. [Распространенные типы событий](#распространенные-типы-событий)
## История появления
Основатель языка, Брендан Айк (англ. Brendan Eich) – программист и создатель языка программирования JavaScript. На момент 2024 года исполнительный директор _Brave Software_. Был нанят в компанию _Netscape_ 4 апреля 1995 года, где была поставлена задача внедрить язык программирования _Scheme_ или что-то похожее в браузер Netscape. Поскольку требования были размыты Айка перевели в группу ответственную за серверные продукты, где он проработал месяц занимаясь улучшением протокола HTTP. В мае разработчик был переброшен обратно, в команду, занимающуюся клиентской частью (браузером), где он немедленно начал разрабатывать концепцию нового языка программирования.
Первоначально язык назывался _LiveScript_ и предназначался как для программирования на стороне клиента, так и для программирования на стороне сервера.
_JavaScript_ изначально был придуман для браузера _Netscape Navigator_. Microsoft первый кто позаимствовал этот язык для своего браузера _Internet Explorer_, добавив в него свои новые возможности. На что Netscape подала в суд в результате чего компания Microsoft выпустила аналог языка _JavaScript_, названный под именем _JScript_. Первым браузером, поддерживающим эту реализацию, был _Internet Explorer 3.0_.
По инициативе компании Netscape была проведена стандартизация языка ассоциацией ECMA. Стандартизированная версия имеет название _ECMAScript_. Первой версии спецификации соответствовал _JavaScript_ версии 1.1. _JavaScript_ после своего появления отличался оригинальностью и настолько понравился, что его начали портировать не только в браузеры, но и в другие среды.
### Создатель языка о его происхождении
Создатель языка JavaScript Brendan Eich [поделился](https://www.jwz.org/blog/2010/10/every-day-i-learn-something-new-and-stupid/) историей происхождения языка и объяснил почему он такой, какой есть:
> JS был обязан «выглядеть как Java», только поменьше, быть эдаким младшим братом-тупицей для Java. Кроме того, он должен был быть написан за 10 дней, а иначе мы бы имели что-то похуже JS.
> что-то вроде PHP, только еще хуже. Его босс Netcsape быстро «зарубил» (в июле 1995, если мне не изменяет память; я сдлелал JS в начале/середине мая), т.к. это был уже третий язык после Java и JS. Было и так трудно обосновать то, что у нас 2 новых языка программирования для web.
> В то время мы должны были двигаться очень быстро, т.к. знали, что Microsoft идет за нами.
> Считайте, что JavaScript (пожалуйста, только не «JScript») спас вас от VBScript.
> 10 дней на то, чтобы сделать лексер, парсер, компилятор в байткод (bytecode emitter), интерпретатор, встроенные классы и декомпилятор. Помощь была только с файлом jsdate.c — от Ken Smith из Netscape (который, по нашему излишне оптимистичному соглашению, склонировал java.util.Date — Y2K баги и т.д. Джеймс Гослинг...).
> Простите, времени было мало для того, чтобы сделать правильную оптимизацию хвостовой рекурсии. 10 дней почти без сна, чтобы сделать JS с чистого листа, заставить его «выглядеть как Java» (я сделал, чтобы он выглядел как C), и тайком протащить туда его спасительные фишки: first class functions (замыкания сделал позже, но они были частью плана сразу) и прототипы (примерно как в языке Self).
> I'll do better in the next life.
## Введение в JavaScript
_JavaScript_ – алгоритмический язык программирования, интерпретируемый язык сценариев, основан на синтаксисе _C_ и _Java_.
_JavaScript_ является объектно-ориентированным языком, но используемое в языке прототипирование обуславливает отличия в работе с объектами по сравнению с традиционными класс-ориентированными языками. Кроме того, _JavaScript_ имеет ряд свойств, присущих функциональным языкам: функции как объекты первого класса, объекты как списки, каррирование, анонимные функции, замыкания, ..., что придаёт языку дополнительную гибкость.
**Популярность языка**
_JavaScript_ является самым популярным языком программирования, используемый для frontend-разработки на стороне клиента. Согласно [рейтингу TIOBE Index](https://www.tiobe.com/tiobe-index), базирующемуся на данных поисковых систем Google, Bing, Yahoo!, Wikipedia, Amazon, YouTube и Baidu, на начало 2023 года JavaScript находится на :trophy: 7 месте, постоянно улучшая свои позиции за последние несколько лет. :trophy: 1 место в [рейтинге GitHub](https://octoverse.github.com/#top-languages-over-the-years) 2021 года. :trophy: 7 место в [рейтинге IEEE](https://spectrum.ieee.org/top-programming-languages-2022) (Институт инженеров электротехники и электроники) в 2022 году. По опросам разработчиков на [StackOverflow](https://survey.stackoverflow.co/2022/#section-most-popular-technologies-programming-scripting-and-markup-languages) в 2022 году JavaScript занимает :trophy: 1 место уже 10 лет подряд как самый часто используемый язык программирования.
**Некоторые отличительные особенности JavaScript:**
- Регистрозависимые конструкции, функции и операторы;
- Все идентификаторы чувствительны к регистру;
- В названиях переменных можно использовать буквы, символ подчёркивания, символ доллара, арабские цифры;
- Названия переменных не могут начинаться с цифры.
**Нотация – устоявшиеся правила записи**
* Все имена маленькими буквами;
* На стыке слов большая буква (camelStyleNotation);
* Переменные и свойства — существительные;
* Массивы и коллекции — существительные во множественном числе;
* Функции и методы — глаголы;
* Названия классов с Большой буквы.
## Комментарии
Комментарии в JavaScript могут быть строчными – начинаются с `//` и блочными (многострочными) – начинаются с `/*` и заканчиваются с `*/`.
```js
// Однострочный комментарий
/*
Многострочный
комментарий
*/
```
## JavaScript в HTML
JavaScript может быть встроен в код HTML с помощью тега ``. Если подключается внешний файл скриптов, то используется атрибут `src` в котором указывается ссылка на файл скрипта.
```html
<script src="outer.js">
```
Встроенный JavaScript-код заключается между тегами ``. Встроенный JavaScript-код будет игнорироваться если у тега указан атрибут `src`.
```html
// Код на JavaScript
```
## Переменные
- Переменная – именованный участок памяти;
- Переменные объявляются ключевыми словами `let`, `const` и `var`;
- Переменные принимают тот тип данных, который в них присваивается;
- В JavaScript допускается присваивать значение переменной, которая еще не определена, но считается хорошим тоном сначала объявить переменную одним из ключевых слов (пункт 2);
- JavaScript язык с динамической типизацией и переменные являются универсальными для всех типов данных, т.е. способны хранить значения любого типа.
**Объявление и инициализация переменных**
```js
// Объявление переменных
const a
let b, c, d
var e
// Иницилизация переменных
const a = 15
let b = c = d = 50
var e = 'string', f = false, g
// Сокращенная запись
x += 1 // Сокращенная запись x = x + 1
// Доступна и для операторов "+", "-", "*", "/", "%"
i++ // инкремент
i-- // декремент
++i // преинкремент
--i // постдекремент
// Пример
var i = 1
let a = i++ // -> a = 1; i = 2;
let b = ++i // -> b = 3; i = 3;
```
### let
- Имеет блочную область видимости (как и [const](#const));
- Переменная объявляемая как `let` ожидает, что её значение может изменяться;
- Переменные `let` и `const` не участвуют в механизме ["поднятия" (hoisting)](#поднятие-hoisting).
### const
- Переменные `const` (как и [let](#let)) доступны только внутри блока, в котором они были объявлены (например, внутри цикла или условного оператора);
- Главное отличие `const` в том, что значение переменной присваивается один раз и не может быть изменено позже;
- В то же время для сложных типов данных таких как массив или объект допускается изменение содержимого, неизменным остаётся лишь ссылка на эту переменную;
- Использование `const` для любой объявляемой переменной, если её значение не должно изменяться, является хорошей практикой, т.к. явно указывает на константное поведение переменной.
```js
const arr = [1, 2, 3]
arr.push(4)
console.log(arr) // -> [1, 2, 3, 4]
```
### var
- `var` был первым способом объявления переменных в JavaScript, до появления стандарта ECMAScript 6 (ES6) в котором были добавлены `let` и `const`;
- При использовании `var` переменная может быть объявлена повторно без выдачи ошибки;
- Имеют функциональную область видимости (function scope), что означает, что они доступны только внутри функции, в которой они были объявлены;
- Если переменная объявлена внутри блока кода (например, внутри цикла или условного оператора), она все равно будет доступна за пределами этого блока;
- Переменные `var` участвуют в механизме ["поднятия" (hoisting)](#поднятие-hoisting);
- Используйте `var` только в случаях, когда вы знаете, что вам нужна функциональная область видимости, и вам нужно поведение _поднятия (hoisting)_. В остальных случаях рекомендуется использовать `let` и `const`.
## Операторы
### Арифметические операторы
- `+` – плюс
- `-` – минус
- `*` – умножить
- `/` – разделить
- `%` – целочисленный остаток от деления
### Операторы сравнения
- `==` – сравнение
- `===` – сравнение с учетом типа
- `!=` – не равно
- `!==` – не равно с учетом типа
- `>` – больше
- `<` – меньше
- `>=` – больше или равно
- `<=` – меньше или равно
### Логические операторы
_(в порядке приоритета)_
- `!` НЕ (отрицание)
- `&&` И (конъюнкция)
- `||` ИЛИ (дизъюнкция)
```js
1 && 2 // -> 2, значение на котором скрипт остановился
1 && 0 // -> 0
0 && 1 // -> 0, т.к. первый операнд false и нет смысла идти дальше
0 || 'false' // -> "false"
```
Операторы сравнения возвращают булево значение либо `true` либо `false`.
Параметры операторов называются _операндами_. Операторы у которых два операнда называются _бинарными_, один операнд — _унарными_, три — _тернарными_ (только один унарный оператором `!` (логическое "не"));
## Выражения и инструкции
### Выражения
_Expression_
```js
5 + 10
'John'
!false
```
### Инструкции
_Statement_
```js
5 + 10
'John'
!false
```
## Типы данных
_Тип данных_ – набор операций, которые можно выполнить над данными. В JavaScript есть формально 8 типов:
1. Boolean – логический;
2. Number – числовой;
3. BigInt – числа произвольной длины;
4. String – строковый;
5. Array – массив;
6. Object – объект;
Тривиальные типы:
7. undefined – неопределенный тип, любая необъявленная переменная имеет такой тип, а также объявленные переменные, которым еще не присвоено значение или несуществующие свойства объекта;
8. null – отсутствие значения. Если переменная имеет значение _null_, то это означает, что в ней ничего не хранится.
### Логический тип
Может принимать константу `true` или `false`. При проверке значения операндов преобразуются в логический тип.
**Создание**
```js
const b = new Boolean(value) // где value значение для булева типа
```
В JavaScript есть как _Boolean-объекты_, так и примитивные _Boolean_ значения. Не смешивайте их. Объект – это объект. В частности, JavaScript любой объект считается `true`, например при неявном приведении типа в операторе `if`.
```js
const x = new Boolean(false)
if(x) {
// этот код будет выполнен
}
```
Не используйте объект _Boolean_ для преобразования к булеву значению. Вместо этого, используйте _Boolean_ как функцию.
```js
const x = Boolean(expression) // предпочтительно
const y = new Boolean(expression) // не используйте
// с использованием двойного отрицания:
const z = !!expression
```
На основании «правила лжи» происходит приведение к логическому типу:
* само значение `false`
* `0` или `-0` (число ноль)
* `''` (пустая строка)
Тривиальные типы
* Значение `NULL`
* `undefined`
* `NaN` (Not a Number)
В современном JavaScript-программировании `new Boolean` не используется.
### Числа
**Создание**
```js
// Полня форма
let n = new Number(value) //где value — числовое значение
//Литеральная форма записи
let n = 25
//Приведение к Number
let n = '123'
Number(n) //123
let n = '132A'
Number(n) //NaN
```
В числовой тип входят как целые числа, так и дробные. Экспоненциальные: $5E3$ (пять на 10 в третьей степени).
В JavaScript можно записать числа в 16-ричной или 8-ричной системе счисления, но только с целыми числами. Например, `const y = 0xFF;`. Префиксом числа восьмеричной системой счисления является цифра `0`. Пример: `const z = 040;` будет 32 (в 10-тичной).
**Особые числовые значения**
В тип `Number` входят не только числа, но и еще три значения:
- +бесконечность (`Infinity`);
- -бесконечность (`-Infinity`);
- особое значение `NaN` (Not a Number – значение числового типа не число). Возникает когда вычисление просто не может быть. Например:
```js
const x = 0 / 0 // -> NaN, деление на ноль
const y = Math.sqrt(-1) // -> NaN, отрицательная степень
// Является ли значение числового типа не числом?
isNaN('x' * 10) // -> true
// Является ли значение бесконечным?
isFinite() // false, если значение NaN или ±Infinity, иначе true
```
### Строки
_Строка_ – набор символов, обрамляется в апострофы или двойные кавычки.
#### Экранирование символов
_Экранирование символов_ – вставка специальных символов через знак обратного слэша после которого идет определенный символ.
* `\'` – одинарные кавычки (апостроф);
* `\"` – двойные кавычки;
* `\\` – обратный слэш (`\u005C`);
* `\b` – backspace;
* `\f` – form feed;
* `\n` – переход на новую строку (`\u000A`);
* `\r` – возврат каретки (`\u000D`);
* `\t` – табуляция (`\u0009`);
* `\v` – вертикальная табуляция;
* `\0` – символ NULL (`\u0000`);
* `\ddd` – octal sequence (3 digits: ddd);
* `\xdd` – hexadecimal sequence (2 digits: dd). Символ Latin-1, заданный двумя шестнадцатеричными цифрами;
* `\udddd` – unicode sequence (4 hex digits: dddd). Символ Unicode, заданный четырьмя шестнадцатеричными цифрами.
В JavaScript все хранится в кодировке _Unicode_. Это означает, что мы можем использовать любые символы _Unicode_ прямо в строке (в Юникоде первые 128 символов совпадают с соответствующими символами в ASCII).
```js
// Полное обозначение символа Unicode
const s1 = '\u2014' // Длинное тире (—)
'\u2564' // Денежный знак валюты тенге (₸)
// Шестнадцатеричное
const s2 = '\x20' // Пробел
```
#### Конкатенация
_Конкатенация_ – объединение (сцепление) строк.
```js
"I " + 'am ' + `in ` + "love " + 'with ' + ` JavaScript`
```
#### Сравнение строк
Строки сравниваются в соответствии со своей позицией в Unicode.
```js
'a' > 'A' // -> true
```
#### Шаблонные литералы
Шаблонные литералы (англ. _Template Literals_, неоф. _Template Strings_ или "шаблонные строки") – способ создания строк, позволяющий встраивать переменные и выражения непосредственно в строку, а также писать многострочные строки и теговые шаблоны.
Синтаксис создания таких строк определяется использованием обратных кавычек (англ. _backticks_), для вставки выражений используется конструкция `${выражение}`:
```js
const name = 'John'
let age = 33
console.log(`Hi, My name is ${name}. Next year I'll turn ${age + 1} years old!`)
```
_Шаблонные литералы_ появились в стандарте ECMAScript 2015 (ES6) и призваны обеспечить более удобный и гибкий способ создания строк благодаря лучшей читабельности и простотой работы с динамическими данными по сравнению с традиционными двойными и одинарными кавычками.
Синтаксис создания таких строк определяется использованием обратных кавычек (англ. _backticks_), для вставки выражений используется конструкция `${выражение}`:
```js
const name = 'John'
let age = 33
console.log(`Hi, My name is ${name}. Next year I'll turn ${age + 1} years old!`)
```
**Интерполяция** в шаблонных строках позволяет легко вставлять любые выражения, включая вызовы функций и переменные.
_Шаблонные литералы_ появились в стандарте ECMAScript 2015 (ES6) и призваны обеспечить более удобный и гибкий способ создания строк благодаря лучшей читабельности и простотой работы с динамическими данными по сравнению с традиционными двойными и одинарными кавычками.
**Многострочный текст**
Шаблонные литералы поддерживают многострочный текст без необходимости использования спецсимволов для перевода строки. Это делает их более удобными для написания кода, особенно для создания HTML-шаблонов или SQL-запросов.
```js
// Создание HTML-кода
const term = 'Template Literals'
const description = 'are literals enclosed by backtick (`` ` ``)'
const html = `
- ${term}
- ${description}
// Создание SQL-запросов
const id = 123
const sql = `SELECT *
FROM users
WHERE id = ${id}`
```
**Тегированные шаблонные строки**
Шаблонные строки могут быть "тегированы" функцией, которая позволяет обрабатывать строку и выражения перед их объединением. Первый аргумент функции тега содержит массив строковых значений. Остальные аргументы относятся к выражениям.
```js
function highlight(strings, nameExp, ...values) {
// Обработка строк и значений
strings[0] // -> "Hello, "
strings[1] // -> "! You're "
strings[2] // -> "years old"
values[0] // -> 32
nameExp // "Jane"
return `${strings[0]}${nameExp} and Welcome${strings[1]}turning ${values[0] + 1}${strings[2]} next year.`
}
let name = 'Jane'
let age = 32
let message = highlight`Hello, ${name}! You're ${age} years old`
console.log(message)
// Hello, Jane and Welcome! You're turning 33 years old next year.
```
**Безопасность**
Использование шаблонных литералов делает код более безопасным, так как автоматически осуществляется экранирование символов. Это помогает предотвратить некоторые виды атак, такие как атаки внедрения SQL.
В шаблонных строках, как и в обычных строках, также можно использовать спецсимволы, такие как перенос строки `\n` или символ возврата каретки `\r`. Над шаблонными строками, как и с обычными, по-прежнему можно использовать встроенные функции JavaScript или методы строк, такие как `.slice()` или `.toLowerCase()`.
### Манипуляции с типами
```js
'2' + '2' // -> строка "22"
2 + '2' // -> строка "22" (строка приоритетнее числа)
'' + true // -> строка "true" (строка приоритетнее булев типа)
2 + true // -> число 3 (число приоритетнее булев типа)
'2' * 10 // -> число 20 (если строка может быть преобразована в число)
'x' * 10 // -> NaN (Not a Namber)
const x = 'x' * 10 // -> NaN
const y = 'y' * 10 //-> NaN
// Однако
x == y // -> false, т.к. NaN != NaN
```
Для проверки типа есть оператор определения типа typeof возвращающая строку соответствующего типа.
```js
typeof 5 // "number"
typeof true // "boolean"
typeof '5' // "string"
```
### Приведение типов
В JavaScript основными преобразованиями типов являются строковые, числовые и логические.
**Преобразование в число**
Числовое значение дают следующие преобразования:
* Умножение строки (которая состоит только из чисел) на число;
* Передать значение как аргумент функции `Number`;
* `parseInt()` – целое число из значения до тех пор, пока не встретится нечисловое значение;
* `parseFloat()` – дробное число из нечислового значения, тоже что и `parseInt()`, но допускается вхождение символа точки.
```js
'5' * 1 // -> целое число 5
'5.5' * 1 // -> дробное число 5.5
parseInt('100.1JS') + 1 // -> целое число 101
parseFloat('10.5JS') // -> дробное число 10.5
Number(true) // -> число 1
Number(false) // -> число 0
```
**Преобразование в строку**
* Строковое преобразование имеет приоритет при попытке сложения двух значений;
* Передача значения как аргумент функции `String`;
* Если в объекте реализован метод `toString()` он будет использован при попытке преобразования объекта в строку.
```js
5 + '' // -> строка '5'
String(true) // -> строка "true"
false + '' // -> строка "false"
```
**Логическое преобразование**
* Логическое сравнение преобразуется для значений при попытке их логического сравнения (`==`, `===`, `&&`, `||` и `!`), в условных конструкциях `if`, `while`, `switch`;
* В логическое значение преобразует функция `Boolean()`.
```js
!!5; // -> true
Boolean(15); // -> true
```
#### Таблица преобразования типов
| Значение | Boolean | Number | String |
|----------------|---------|-----------|-------------------|
| true | true | 1 | "true" |
| false | false | 0 | "false" |
| 0 | false | 0 | "0" |
| 1 | true | 1 | "1" |
| "0" | true | 0 | "0" |
| "1" | true | 1 | "1" |
| NaN | false | NaN | "NaN" |
| Infinity | true | Infinity | "Infinity" |
| -Infinity | true | -Infinity | "-Infinity" |
| "" | false | 0 | "" |
| "строка" | true | NaN | "строка" |
| [ ] | true | 0 | "" |
| { } | true | NaN | "[object Object]" |
| [10] | true | 10 | "10" |
| [10,20] | true | NaN | "10,20" |
| ["строка"] | true | NaN | "строка" |
| ["один","два"] | true | NaN | "один,два" |
| function(){} | true | NaN | "function(){}" |
| null | false | 0 | "null" |
| undefined | false | NaN | "undefined" |
## Управляющие конструкции
### if
Управляющая конструкция `if` выполняет инструкции если условие истинно.
В `if` может быть сколько угодно `else if`. Последнее `else` (без условий) можно опустить, хотя рекомендуется его использовать как «отстойник».
```js
if (condition) {
statement1
statement2
} else if (condition 2) {
statement3
statement4
} else {
statement5
statement6
}
```
### Тернарный оператор
_Тернарный оператор_ – это оператор с тремя операндами. В JavaScript единственный тернарный оператор это сокращенный вариант записи условной конструкции `if..else..`.
```js
const result
// Обычная условная конструкция
if (условие)
result = 'условие истинно'
else
result = 'условие ложно'
// То же условие через тернарный оператор
b = (a > 1) ? 'условие истинно' : 'условие ложно'
```
Скобки в условии тернарного оператора можно опустить, но для лучшей читаемости не рекомендуется.
### switch
Оператор переключения `switch` позволяет проанализировать множество вариантов значений, используя для анализа числовое или строковое значение.
Внутри конструкции `switch` обычно применяют оператор `break`, т.к. в отсутствии данного оператора если `switch` встретит значение которое соответствует значению в `case`, он выполнить все последующие (нижележащие) инструкции игнорируя все `case` словно их нет.
Оператор `default` сработает если интерпретатор не попадет ни в один `case`.
```js
const a = 2
switch (a) {
case 0:
case 1:
case 2:
console.log('Two')
break;
case 3:
case 4:
case 5:
default:
alert("It's many!")
}
```
### for
Цикл `for` – многократное выполнение одних и тех же действий заранее известное количество раз.
_Итерация_ – однократное выполнение (шаг) цикла.
**Как работает цикл for**
```js
for (часть A; часть B; часть C)
часть D (тело цикла)
```
Когда интерпретатор встречает цикл `for`, он сперва заходит в `часть А` и выполняет то, что там написано ровно один раз. `часть В` выступает как условие, если оно истинно, то интерпретатор заходит в `часть D` (тело цикла), после выполнения которого переходит в `часть С`. Потом возвращается в `часть В` (проверяет условие) и если там истина, то переходит в `часть D` и далее как по треугольнику происходит переход:
> часть В => часть D (тело цикла) => часть С
>
> До тех пор пока часть В не вернет false
Любую из частей цикла for можно опустить, главное чтобы присутствовали точки с запятой как часть синтаксиса.
Если в `часть А` необходимо выполнить несколько инструкций, то разделять их следует запятой.
**Цикл for с пустым телом**
Ниже цикл возводит значение переменной `result` в 10-ую степень.
```js
for (let i = 1, result = 2, exp = 10; i < exp; result += result, i++){}
console.log(result) // -> 1024
```
**Цикл for с continue и break**
`continue` в циклах `for`, `while` и `do..while` прерывает текущую итерацию и переход к следующей.
`break` немедленно заканчивает цикл и выходит за операторные скобки.
```js
for (let i = 0; i < 10; i++) {
if (i == 4)
continue
if (i == 8)
break
}
```
### while
* Условие проверяется ПЕРЕД очередным проходом;
* Выполняется пока условие истинно;
* Если условие изначально ложно – не выполнится ни разу.
```js
let num = 1
while (num < 1000) {
num *= 2
if(num == 32) continue
if(num == 512) break
console.log(num)
}
```
### do..while
* Условие проверяется ПОСЛЕ очередного прохода;
* Выполняется пока условие истинно;
* Если условие изначально ложно – выполнится хотя бы один раз.
```js
let num = 1
do {
num *= 2
if (num == 32) continue
else if (num == 512) break
console.log(num)
} while (num < 1000)
```
Если в теле цикла `do..while` все лишь одна инструкция, то операторные скобки можно опустить.
```js
let a = 0
do a++
while (a <= 5) // Одна инструкция в теле цикла
console.log(a) // -> 5
```
### for..in
Предназначен для прохода по массивам, коллекциям, объектам.
```js
for (let prop in navigator) {
console.log(prop)
}
```
### Метки
Иногда бывает нужно прервать вложенный цикл или цикл с n-количеством вложенности. В JavaScript это можно организовать с помощью меток. Названия меток не должны начинаться с цифры.
```js
let i = 1
outer: while (i < 10) {
inner: for (let j = 1; j <= i; j++) {
if (j > 2)
continue inner
if (i * j > 10) {
console.log(i, j)
break outer
}
}
i++
} // -> 6, 2
```
### try..catch..finally
`try..catch..finally` – оператор обработки исключений служит для написания кроссбраузерных приложений. Так как при возникновении ошибки в JavaScript исполнение программы останавливается, конструкция `try..catch..finally` позволяет пропустить ошибочную конструкцию и перейти к следующей.
Сначала JavaScript пытается выполнить все что находится в блоке `try`, если внутри блока `try` ошибки не возникнет, то содержимое блока `catch` игнорируется.
Содержимое блока `finally` выполняется при любом случае, вне зависимости от того возникла ошибка или нет.
Разница между кодом в блоке `finally` и кодом в блоке всей этой конструкции проявляется в JavaScript только в случае если в блоке `catch` произойдет ошибка.
В случае возникновения ошибки в `catch` программа остановится за исключением если есть блок `finally`. В таком случае блок `finally` выполнится, а все что после него нет.
Допускается вкладывать конструкции `try..catch..finally` внутри друг друга.
```js
try {
console.log('До ошибки в блоке try')
throw new Error() // В случае ошибки попадаем в блок catch
console.log('После ошибки в блоке try')
} catch(e) { // В переменную "e" заносится информация об ошибке
console.log('Сообщение об ошибке: ' + e.message)
} finally {
console.log('Сообщение из блока «finally»')
}
console.log('Сообщение после конструкции try..catch..finally')
```
## Функции
_Функция_ – некоторый именованный набор кода, который определяется один раз и может вызываться многократно.
* Имена функций чувствительны к регистру;
* Если какой-либо фрагмент кода повторяется или предполагается использовать несколько раз, то это явный признак того, чтобы завести функцию (подпрограмму);
* Внутри функции доступен массив `arguments`, в котором находятся переданные аргументы функции, а сама функция может быть продекларирована без единого аргумента;
* Если функция ожидает два параметра, а передаем мы только один, то второй аргумент будет иметь значение `undefined`.
```js
function sayHello(name) { // Формальные параметры
if (name == null)
name = 'Stranger'
console.log('Hello, ' + name)
}
sayHello('John') // -> Hello, John
sayHello('Jane') // -> Hello, Jane
sayHello() // -> Hello, Stranger
```
### Области видимости
* Глобальные переменные объявляются до описания функций, объявляются вне тела функции и могут быть причиной сложно находимых ошибок;
* Локальные переменные явно объявляются в теле функции и аргументы функции всегда локальные переменные;
* У каждой функции своя область видимости;
* Локальные переменные «живут» столько сколько живет функция.
В примере ниже в функции `foo()` произойдёт перезапись глобальной переменной `x`. В функции же `bar()` с использованием ключевых слов `var`, `let`, `const`.
```js
var x = 'x-global'
function foo () {
x = 'x-local-foo'
return x // Возвратит глобальную переменную "x"
}
foo() // -> x-local-foo
function bar () {
var x = 'x-local-bar'
return x // Возвратит локальную переменную "x"
}
bar() // -> x-local-bar
```
Скорее правильней считать переменные не как глобальные или локальные, а в контексте вложенных функций, как родитель-ребенок. В примере ниже вызов переменной `x` в функции `inner()` произойдет из глобальной области видимости, т.к. переменная `x` не продекларирована внутри самой функции `inner()` и её родительской функции `outer()`. Вызов переменной `y` произойдет из родительской функции `outer()`, что касается переменной `z`, то она передается как аргумент функции `inner()`, что сама по себе является локальной.
```js
function echo (str) {
console.log(str.toString())
}
let x = 'x-global', y = 'y-global', z = 'z-global'
function outer() {
let y = 'y-local'
function inner(z) {
echo(x) // -> x-global
echo(y) // -> y-local
echo(z) // -> z-local
return 'inner function'
}
return inner('z-local')
}
outer() // -> inner function
```
В этом примере нельзя вызвать функцию `inner()` из глобальной области видимости. Она может быть вызвана только внутри функции родителя — `outer()`.
**Засада с областью видимости**
В коде ниже можно предположить, что внутри тела функции мы изменим значение глобальной переменной.
```js
var x = 100
function foo(x) {
if(x)
x = 10
else
var x = 20
}
foo(true)
console.log(x) // -> 100
```
Но при выполнении кода мы получим значение `100`, т.к. JavaScript перед исполнением кода, помимо синтаксической проверки также исправляет код и выполнит его так, как если бы он выглядел следующим образом:
```js
var x = 100
function foo(x) {
var x
if (x)
x = 10 // это и
else
x = 20 // это относится к локальной области видимости
}
foo(true)
console.log(x) // -> 100
```
### Функция как тип данных
Функция в JavaScript является таким же типом данных, как Boolean, String, Number, Object, ... Это значит, что с функциями можно производить такие же действия, как и с обычными типами.
```js
function echo(str) {
console.log(str.toString())
}
let print = echo
print('Теперь «print» это точная копия функции «echo»')
```
### Свойства функций
`имя_функции.length` – возвратит количество ожидаемых параметров функции.
```js
function foo(arg1, arg2, arg3) {}
// Сколько параметров ожидает функция?
console.log(foo.length); // -> 3
```
При создании функции автоматически создается объект `arguments`. Свойство `arguments.length` возвращает количество фактически переданных параметров.
```js
function getArgs() {
return arguments.length
}
getArgs(1, 2, 3, 4, 5, 6, 7, 8, 9) // -> 9
```
Все переданные параметры функции доступны в объекте `arguments` каждый под своим порядковым номером начиная с нуля.
```js
function sum() {
let i = result = 0
while (arguments[i]) {
result += arguments[i]
i++
}
return result
}
console.log(sum(1, 2, 3, 4, 5, 6, 7, 8, 9)) // -> 45
```
### Анонимная функция
_Анонимная функция_ – функция, объявляемая без определённого имени, который мог бы служить идентификатором для доступа к ней. В примере ниже анонимная функция присваивается переменной `sum` после чего, `sum()` становится функцией.
```js
const sum = function(val) {
return val + val;
}
sum(5) // -> 10
```
Разница между функциями декларированные словом `function` и функциями присваиваемые переменным в том, что первых можно вызывать до её объявления, т.к. в этом случае сработает механизм _hoisting_ (поднятие).
В коде ниже вызов функции `foo()` не вызовет ошибку, в то время как вызов `bar()` выдаст ошибку:
```console
TypeError: bar is not a function
```
Так как на момент выполнения скрипта функция `bar()` не была создана, а появилась только как результат выражения присваивания переменной.
```js
foo()
bar() // -> TypeError: bar is not a function
const bar = function(args) {
statements
}
function foo(parameters) {
statements
}
```
### Стрелочные функции
Стрелочные функции предоставляют более краткую форму записи функций.
```js
// Стандартная функция
function sum(a, b) {
return a + b
}
// Стрелочная функция
const add = (a, b) => a + b
```
**Особенности стрелочных функций**
* Если функция принимает только один параметр, скобки вокруг параметров можно опустить;
* Если тело функции состоит из одного выражения, то его не обязательно заключать в фигурные скобки, а оператор `return` можно также опустить;
* Стрелочные функции не создают собственный контекст `this`, вместо этого они заимствуют контекст от родительской области видимости;
* Стрелочные функции не могут быть использованы с оператором `new` для создания экземпляров объектов;
* Стрелочные функции не имеют доступа к объекту `arguments`.
### Замыкания
_Замыкания_ – способность функции захватывать переменные родительского контекста.
```js
function makeAdd(base) {
return function(num) {
return num + base;
}
}
const addTen = makeAdd(5)
addTen(10) // -> 15
```
**Пример со сравнением чисел**
При первом вызове `compare(10)` функция возвратит внутреннюю функцию при этом сохранив в переменной `x` значение `10`.
```js
function compare(x) {
return function innerCompare(y) {
if (x === y) return null
return x < y
}
}
const checkNum = compare(10) // -> function "innerCompare"
checkNum(9) // -> false
checkNum(10) // -> null
checkNum(11) // -> true
```
### Рекурсия
_Рекурсия_ – вызов функции саму себя. Нахождение факториала числа наиболее распространённый пример рекурсивного вызова функции.
```js
function factorial(n) {
if(n === 0) return 1
return n * factorial(n - 1)
}
factorial(5) // -> 120
```
### Поднятие (Hoisting)
Под поднятием (hoisting) в JavaScript называют механизм поднятия в начало кода объявленных переменных и функций, чтобы они могли быть использованы до своего фактического объявления в коде.
На практике переменные и функции остаются на том же месте, где вы их объявили. Вместо этого, интерпретатор JavaScript сначала сканирует код и создает переменные и функции в памяти на этапе компиляции (до фактического выполнения кода). Это позволяет JavaScript использовать переменные и функции до их фактического объявления в коде без выдачи ошибок.
Здесь следует уточнить, что "поднимаются" только объявления, но не инициализация (присваивание значений).
**Поднятие функций**
Функция `hi()` исполняется без ошибок невзирая на позднее объявление:
```js
hi() // -> "Greetings"
function hi() {
return "Greetings"
}
```
**Поднятие имён переменных**
Одно из отличий `var` перед `let` и `const` в том, что последние имеют блочную область видимости:
```js
console.log(x) // -> undefined
var x = 1
console.log(y) // -> ReferenceError:
// Cannot access 'y' before initialization
const y = 2
```
## Объекты
* Объектный тип данных – входят все объекты JavaScript (свойства, методы);
* Объект – коллекция данных (свойств), функций (методов), и, возможно, других объектов;
* Объект явно создается с помощью оператора `new`, литерала объекта `{}` или метода `Object.create()`;
* Объект явно уничтожается при уничтожении переменной или присваивании переменной значения `null`;
* Когда мы присваиваем значение некоему свойству объекта, которого нет в объекте, происходит создание свойства;
* В JavaScript почти всё является объектом. Даже примитивные типы данных при необходимости могут "упаковываться" в объекты-обёртки. Например, `const x = 17.5` эквивалентно `const x = new Number(17.5)`.
### Создание объекта
```js
// Создание объекта с помощью конструктора Object()
let Book = new Object()
// Сокращённая запись с помощью литерала объекта
let User = {
say() {
console.log('Hello!')
}
}
// Создание объекта с методом Object.create() на основе прототипа (User)
const John = Object.create(User)
John.say() // -> "Hello!"
// Создание свойств
Book.title = 'JavaScript. Подробное руководство' // String
Book['author'] = 'Дэвид Флэнаган' // Имя как ключ массива
Book.year = 2021 // Number значение
Book.isAvailable = true // Boolean значение
Book.order() // вызов метода
// Недопустимая форма записи
obj.word1-word2 = true // -> Ошибка, SyntaxError
obj.'property' = true // -> Ошибка, SyntaxError
```
Другие способы создания объекта с помощью функции-конструктора и синтаксиса классов рассмотрены далее в разделе [Объектно-ориентированное программирование](##объектно-ориентированное-программирование).
### Свойства объекта
Если имя свойства содержит символы недопустимые в названии переменной (пробелы, дефисы) или оно совпадает с зарезервированным словом (например: `var`, `for`, `instanceof`, ...), то необходимо имя свойства заключить в кавычки. В этом случае обращаться к свойству нужно с помощью квадратных скобок. Например, `objName['object\'s property']`.
Если свойство состоит из одного слова, то можно не заключать его в кавычки. Названия свойств с пробелами также обрамляются кавычками.
```js
const Car = {
speed: 220,
color: 'orange',
'year': 2025,
'sport car': false
}
const Audi = Car // копия объектв
Audi['car-body'] = 'coupe'
```
#### Работа со свойствами объекта
Методы для работы со свойствами объекта рассмотрены в разделе [Управление свойствами объекта](#управление-свойствами-объекта)
_Удаление свойства объекта_
```js
delete Audi['car-body']
delete Audi.color
```
_Проверка на наличие свойств в объекте_
```js
'color' in Audi // -> false
'sport car' in Audi // -> true
```
_Динамическое обращение к свойствам объекта_
Названия свойств могут формироваться динамически путём результата выражения.
```js
const User = {
isAdmin: 'yes',
'2': 0
}
console.log(User[1 + 1]) // -> 0, обращение к свойству '2'
const x = 'is'
console.log(User[x + 'Admin']) // -> "yes"
```
#### Перебор свойств объекта
В принципе, если бы названия свойств объекта состояли только из чисел, то можно было бы воспользоваться циклом `for`. Например:
```js
const NumberObject = {
1 : 'свойство 1',
2 : 'свойство 2',
3 : 'свойство 3',
4 : 'свойство 4',
}
for (let i = 1; i in NumberObject; i++) {
console.log(NumberObject[i])
}
```
Для прохода по объектам или коллекциям используется конструкция `for..in`.
```js
const AssocObj = {
0 : 'male',
age : 21,
'name' : 'John',
true : false
}
for (let current in AssocObj) { // где current – имя свойства
console.log(current + ': ' + AssocObj[current])
}
```
### Сравнение объектов
При присваивании переменной, которая хранит в себе объект происходит ссылка на этот самый объект. И при сравнении двух переменных возвратится значение `true` не по причине одинакового содержимого двух объектов, а потому, что обе переменные являются ссылкой на один и тот же объект. Так, в примере ниже объект `o1` возвратит `true` при сравнении с объектом `o2`. И все дальнейшие изменения с объектов `o2` отобразятся и на объекте `o1`.
В то же время, несмотря на одинаковое содержимое объектов `o1` и `o3` они возвратят `false` при сравнении, т.к. с точки зрения ООП это разные объекты.
```js
const o1 = { x: 150 }
const o2 = o1 // -> ссылка на объект o1
const o3 = { x: 150 }
console.log(o1 == o2) // -> true
console.log(o1 == o3) // -> false
// Измение значение свойства "x" объекта "o2"
o2.x = 200
// Значение свойства "x" объекта "o1" также изменилось
console.log(o1.x)
```
### Создание методов в объекте
Методы создаются путем присваивания анонимной функции.
```js
const Methods = {
one: function() {
console.log('This is method "one"')
},
two: function(param) {
console.log('I am a ' + param)
}
}
methods.one() // -> This is method "one"
methods.two('JavaScript Student') // -> I am a JavaScript Student
```
**Ключевое слово `this`?**
Ключевое слово `this` используется в объектах для передачи ссылки на объект внутри которого он вызывается. Вместо `this` сработало бы и имя объекта, но принято использовать именно `this`.
```js
const MyObject = {
property: 'property value',
method: function() {
console.log(this.property)
},
}
MyObject.method() // -> "property value"
```
### Методы объекта Object
#### Доступ к свойствам объекта
* `Object.keys(obj)` – возвращает массив ключей объекта.
```js
const person = {
name: 'John',
age: 32,
city: 'Almaty'
}
const keys = Object.keys(person)
console.log(keys) // -> ["name", "age", "city"]
```
* `Object.values(obj)` – возвращает массив значений объекта.
```js
const person = {
name: 'Jane',
age: 31,
city: 'Astana'
}
const values = Object.values(person)
console.log(values) // -> ["Jane", 31, "Astana"]
```
* `Object.entries(obj)` – возвращает массив пар "ключ-значение" объекта.
```js
const person = {
name: 'John',
age: 32,
city: 'Shymkent'
}
const entries = Object.entries(person)
console.log(entries) // -> [["name", "John"], ["age", 33], ["city", "Shymkent"]]
```
* `hasOwnProperty(prop)` – проверяет, принадлежит ли свойство непосредственно объекту.
```js
const person = {
name: 'Jane',
age: 31
}
console.log(person.hasOwnProperty('name')) // -> true
console.log(person.hasOwnProperty('toString')) // -> false
```
* `valueOf()` – возвращает примитивное значение объектов Number, Boolean, ...
```js
const n = new Number(5)
n.valueOf() // -> 5
const obj = {
name: 'John',
age: 32,
valueOf: function() {
return this.age;
}
}
console.log(obj + 10) // -> 42 (valueOf() преобразует объект в число)
```
* `имяОбъекта.hasOwnProperty(имяСвойства)` – является ли свойство/метод унаследованным.
```js
const user = {
id: 123,
login: 'Jane',
password: '******',
}
console.log(user.hasOwnProperty('login')) // -> true
console.log(user.hasOwnProperty('toString')) // -> false (унаследовано от прототипа)
Object.prototype.myProperty = 'myValue'
// Напечатает только собственные свойства и методы
for (let i in user) {
if (user.hasOwnProperty(i)) {
console.log(user[i])
}
} // -> 123, Jane, ******
```
* `имяОбъекта.propertyIsEnumerable(имяСвойства)` – является ли свойство перечисляемым.
```js
const user = {
name: "John"
}
Object.defineProperty(user, 'age', {
value: 32,
enumerable: false
})
console.log(user.propertyIsEnumerable('name')) // -> true
console.log(user.propertyIsEnumerable('age')) // -> false (свойство не перечисляемое)
```
* `Object.prototype.isPrototypeOf(объект)` – является ли прототип прототипом объекта.
```js
const proto = {
greet: function() {
console.log('Hello! World')
}
}
const obj = Object.create(proto)
console.log(proto.isPrototypeOf(obj)) // -> true
```
#### Управление свойствами объекта
* `Object.defineProperty(obj, prop, descriptor)` – определяет новое свойство или изменяет существующее.
```js
const person = {}
Object.defineProperty(person, 'name', {
value: 'John',
writable: false, // Нельзя изменить значение
enumerable: true, // Можно перечислить свойство
configurable: false // Нельзя удалить или изменить конфигурацию свойства
})
console.log(person.name) // -> "John"
person.name = 'Jane' // Ошибка, свойство name не перезаписывается
```
* `Object.defineProperties(obj, props)` – определяет несколько свойств.
```js
const person = {}
Object.defineProperties(person, {
name: {
value: 'John',
writable: false
},
age: {
value: 32,
writable: true
}
})
console.log(person.name) // -> "John"
console.log(person.age) // -> 32
person.age = 33 // Изменение значения свойства age
console.log(person.age) // 33
```
* `delete obj.prop` – удаляет свойство из объекта.
```js
const person = {
name: 'John',
age: 32
}
delete person.age
console.log(person.name) // "John"
console.log(person.age) // undefined
```
#### Прочие методы объекта
* `Object.assign(target, ...sources)` – копирует свойства из исходных объектов в целевой объект.
```js
const target = { name: 'John' }
const source1 = { age: 32 }
const source2 = { city: 'Almaty' }
Object.assign(target, source1, source2)
console.log(target) // -> { name: 'John', age: 32, city: "Almaty" }
```
* `Object.freeze(obj)` – делает объект неизменяемым.
```js
const user = {
name: 'Jane',
age: 31
}
Object.freeze(user)
user.age = 30 // -> false
console.log(user) // { name: "Jane", ag }
```
* `Object.seal(obj)` – запрещает добавление новых свойств, но разрешает изменение существующих.
```js
const user = {
name: 'John',
age: 32
}
Object.seal(user)
user.age = 31 // Свойство "age" будет изменено
user.sex = 'male' // Свойство "sex" не будет добавлено
delete user.name // Свойство "name" не будет удалено
console.log(user) // -> { name: "John", age: 32 }
```
* `Object.is(value1, value2)` – определяет, являются ли два значения одинаковыми.
```js
console.log(Object.is(10, 10)) // -> true
console.log(Object.is('hello', 'world')) // -> false
console.log(Object.is(NaN, NaN)) // -> true
console.log(Object.is(0, -0)) // -> false
```
### Создание метода из имеющейся функции
```js
function foo() {
console.log(this.name)
}
const users = {
name: 'John',
getName: foo, // Присваивание имеющейся функции
}
users.getUserName = foo // Присваивание имеющейся функции
users.getName() // -> John
```
### call / apply
Любую функцию в JavaScript можно вызывать в контексте любого объекта. Это нужно когда нет необходимости громоздить объект лишними функциями. Для этого есть методы `call` и `apply`. Метод `apply` очень похож на `call`, за исключением передачи аргументов. В `apply` используется массив аргументов вместо списка именованных параметров.
```js
function outer(x, y) {
return this.num + x + y
}
const ObjectOne = {
num: 10,
}
// Первый аргумент задает значение this внутри функции
outer.call(ObjectOne, 50, 190); // -> 250
// Вызов функции внутри объекта
const ObjectTwo = {
num: 15,
method: function() {
return outer.apply(this, [12, 8])
},
}
ObjectTwo.method() // -> 35
```
## Массивы
* Массив – упорядоченный набор данных;
* Доступ к элементам массива осуществляется по его номеру (индексу);
* Элементы массива нумеруются с нуля.
Элементы массива доступны по их индексу (порядковым номером) и могут содержать что угодно (числовые, строковые данные, функции, и т.д.). В этом плане массивы в JavaScript похожи на объекты с той разницей, что элементы не именованные, а индексированные.
### Создание и работа с массивами
```js
// С помощью литерала
let arr = [] // Иницилизация пустого массива
arr = ['string', 1, true]
typeof arr // -> "object" (массив это Объект)
// С помощью конструктора Array
let arr2 = new Array(5) // -> [undefined × 5]
arr2 = new Array(5, 10, 15, 20, 25, 30)
// Заполнение уже созданного массива
arr['name'] = 'John'
arr['surname'] = 'Doe'
arr.age = 30
// Создадим пару функций для последующего добавления их в массив
function sayHello() {
return 'Hello! World'
}
const multiple = function() {
let result = 1, i = 0
do {
result *= arguments[i]
i++
} while(arguments[i])
return result
}
// Добавление данных при иницилизации массива
const user = [30, 'male', sayHello, multiple, true]
// Обращение к элементам массива
user[0] // -> 30
user[2]() // -> "Hello! World", произошел вызов функции «sayHello»
user[3](2, 2, 4, 2, 5, 3, 10) // -> 4800, вызов функции «multiple»
```
### Добавление элементов в созданный массив
Чтобы безошибочно добавить элемент в существующий массив, можно воспользоваться свойством `length`, который возвращает количество(длину) элементов массива. Здесь действует аксиома:
> _Индекс последнего элемента массива на единицу меньше длины массива_
Инициализируемый массив `myArray` имеет длину `length = 3`, т.к. последний занятый индекс 2.
После присваивания значения ячейке массива с индексом `10`, в массиве `myArray` хранятся 11 элементов. Элементы с порядковым номером с 4 по 9 имеют значение `undefined`.
```js
const myArray = [0, false, '25']
myArray[myArray.length] = 'еще один элемент в массиве'
console.log(myArray[3]) // -> "еще один элемент в массиве"
// Длина массива
myArray.length // -> 4
myArray[10] = 'x'
myArray.length // -> 11
myArray // [0, false, '25',
// 'еще один элемент в массиве', undefined × 4, 'x']
```
Свойство `length` у массивов доступны не только на чтение, но и на запись. Таким же образом можно сократить количество элементов в массиве.
```js
myArray.length = 3
myArray // -> [0, false, '25']
```
### Перебор элементов массива
```js
const array = ['Jane', 36, true]
array.length = 2 // Сокращение массива (3-ий элемент будет удален)
array[7] = 'z'
for(let i = 0; i < array.length; i++) {
console.log(i + ': ' + array[i])
/* Напечатает:
0: Jane
1: 36
2-6: undefined (x5)
7: z
*/
}
for(let j in array) {
console.log(j + ': ' + array[j])
/* Напечатает:
0: John
1: 25
7: z
*/
}
```
Цикл `for..in` чаще всего оказывается наиболее предпочтительным. В примере выше он опустил все элементы со значением `undefined`, однако он выведет элемент со значением `undefined` если таковой был присвоен явно, например, `array[25] = undefined`.
При удалении элемента массива, индекс массива принимает значение `undefined`. Причем есть разница от `undefined` который произошел в результате удаления и явно присваиваемого `undefined`. В первом случае, значение `undefined` рассматривается как неизвестное(неопределенное) значение, во втором случае, как конкретное значение типа `undefined`.
### Удаление элемента массива
```js
delete array[2]
array // ["Jane", 36, undefined]
array[array.length] = undefined
array // ["Jane", 36, undefined, undefined]
```
### Методы для работы с массивами
#### Создание массивов
* `Array.from()` – создает новый массив из итерируемого объекта или псевдомассива.
```js
// Массив из строки
Array.from('hello') // -> ["h", "e", "l", "l", "o"]
// Массив из NodeList
let paragraphs = document.querySelectorAll('p')
Array.from(paragraphs) // -> массив элементов
// Создание массива с преобразованием элементов
let numbers = [1, 2, 3]
Array.from(numbers, n => n * 2) // -> [2, 4, 6]
```
* `Array.fromAsync()` – создает новый массив из асинхронного итерируемого объекта.
```js
async function getFiles() {
let dir = await openDir('.')
let files = []
for await (let file of dir) {
files.push(file)
}
return files
}
let filesArr = await Array.fromAsync(getFiles()) // -> массив файлов в директории
```
* `Array.of()` – создает новый массив из переданных аргументов.
```js
Array.of('Hi', true, 3, [4], {5: 6}) // -> ['Hi', true, 3, [4], {5: 6}]
```
#### Доступ к элементам массива
* `at()` – возвращает элемент массива по заданному индексу.
```js
// Получение первого элемента
let arr = [1, 2, 3]
let firstElement = arr.at(0) // -> 1
// Получение последнего элемента
let arr = [1, 2, 3]
let lastElement = arr.at(-1) // -> 3
```
* `entries()` – возвращает итератор, который содержит пары `[ключ, значение]` для каждого элемента массива.
```js
let arr = ['a', 'b', 'c']
for (let [index, value] of arr.entries()) {
console.log(index, value)
}
// Напечатает:
// 0 "a"
// 1 "b"
// 2 "c"
```
* `keys()` – возвращает итератор, который содержит ключи (индексы) элементов массива.
```js
let arr = ['a', 'b', 'c']
for (let key of arr.keys()) {
console.log(key)
}
// Напечатает:
// 0
// 1
// 2
```
* `values()` – возвращает итератор, который содержит значения элементов массива.
```js
let arr = ['a', 'b', 'c']
for (let value of arr.values()) {
console.log(value)
}
// Напечатает:
// "a"
// "b"
// "c"
```
#### Поиск элементов массива
* `every()` – проверяет, удовлетворяют ли все элементы массива заданному условию.
```js
const numbers = [1, 2, 3, 4, 5]
const allPositive = numbers.every(number => number > 0) // -> true
const allEven = numbers.every(number => number % 2 === 0) // -> false
```
* `filter()` – создает новый массив с элементами, которые прошли проверку заданным условием.
```js
const numbers = [1, 2, 3, 4, 5]
const evenNumbers = numbers.filter(number => number % 2 === 0) // -> [2, 4]
```
* `findLast()` – возвращает последний элемент массива, который удовлетворяет заданному условию.
```js
const numbers = [1, 2, 3, 4, 5]
const lastEvenNumber = numbers.findLast(number => number % 2 === 0) // -> 4
```
* `findLastIndex()` – возвращает индекс последнего элемента массива, который удовлетворяет заданному условию.
```js
const numbers = [1, 2, 3, 4, 5]
const lastEvenNumberIndex = numbers.findLastIndex(number => number % 2 === 0) // -> 3
```
* `some()` – проверяет, удовлетворяет ли хотя бы один элемент массива заданному условию.
```js
const numbers = [1, 2, 3, 4, 5]
const hasEvenNumber = numbers.some(number => number % 2 === 0) // -> true
const allNegative = numbers.some(number => number < 0) // -> false
```
#### Получение строки из массива
* `toString()` – приводит к строке массив, разделяя элементы запятыми;
* `join()` – делает то же самое, что и toString() за тем исключением, что в join() в качестве параметра можно передать разделитель.
```js
const foo = () => 'Hello! World'
const bar = [20, 2, 25, foo]
const baz = bar.toString()
const qux = bar.join(' • ')
console.log(baz) // -> "20,2,25,() => 'Hello! World'"
console.log(qux) // -> "20 • 2 • 25 • () => 'Hello! World'"
```
#### Конкатенация массивов
* `concat()` – возвращает новый массив в котором объеденины все перечисленные через запятую параметры. При этом исходный массив остаётся неизменным.
```js
const foo = [1, 2]
const foo = [3, 4]
foo.concat(foo, 5, 6) // -> [1, 2, 3, 4, 5, 6]
foo // -> 1, 2; Массив foo остается неизменным
```
Оператор `+` в контексте массива приводит каждый массив к строке.
```js
const bar = [1, 2] + [3, 4] // -> "1,23,4"
```
#### Получение части массива
* `slice()` – вырезает часть массива. Функция `slice` не изменяет массив на котором вызывается эта функция, а в качестве результата возвращает копию массива.
В функциях для получения части массива (функции `slice`, `splice`) первый параметр (или если передается только один параметр) отсчет позиции начинается с нуля, если передается отрицательное значение, то отсчет начинается с конца и с единицы.
Если передается один параметр, то возвратит часть массива начиная с позиции переданного параметра и до конца массива.
```js
const array = [23, 11, 5, 16, 98, 55]
array.slice(3) // -> 16, 98, 55
```
Можно передать отрицательное значение, тогда отсчет элементов массива начнется с конца.
```js
array.slice(-2) // -> 98, 55
```
Вернется часть массива с позиции первого параметра до позиции второго параметра. Отсчет позиции второго параметра начинается сначала.
```js
array.slice(2, 4) // -> 5, 16
```
В случае передачи неверных данных возвратится пустой массив.
```js
array.slice(5, 2) // -> []
```
#### Вставка и удаление в любом месте
* `splice()` – вырезает или вставляет элементы в массив.
_С одним параметром_. Если передается один параметр, то возвратится часть массива начиная с начала и длиной переданного параметра. Отсчет начинается с единицы.
```js
const array = [14, 22, 'third', true, ['array']]
array.splice(3) // -> ["14, 22, third"]
```
_С двумя параметрами_. Если передается два параметра, то возвратится часть массива начиная с позиции первого параметра и длиной второго параметра.
```js
array = [14, 22, 'third', true, ['array']]
const third = array.splice(2, 1) // -> ["third"]
array // -> ["14, 22, true, array"]
```
_С тремя параметрами_. Если передается три и более параметра, то произойдет вставка всех элементов, переданные третьим (и более если есть) параметром(ов). Первый параметр означает перед каким элементом массива произойдет вставка, второй параметр – количество элементов, которые необходимо вырезать.
```js
const sourceArray = ['1st', '2nd', '4th', '5th']
sourceArray.splice(2, 0, '3rd') // -> ["1st", "2nd", "4th", "5th"]
sourceArray.join() // -> ["1st,2nd,3rd,4th,5th"]
```
Функции `slice()` и `splice()` отличаются тем, что в функции `splice()` второй параметр отсчитывается не с начала массива, а с позиции равной первому параметру. Также в функции `splice()` можно передать три и более параметра. В этом случае происходит вставка новых элементов в массив.
#### Сортировка массива
* `revers()` – реверс массива, функция ничего не возвращает и применяется непосредственно к самому массиву.
```js
const array = [23, 11, 5, 16, 98, 55]
array.reverse() // -> 55, 98, 16, 5, 11, 23
```
* `sort()` – сортирует массив как строки (даже если массив имеет только числовые значения). Функция `sort()` может принимать необязательный параметр — имя функции. Если функция указана, то элементы массива будут отсортированы согласно значениям, возвращаемых функцией. Если параметр не указан, массив будет отсортирован в лексикографическом порядке (возрастающий порядок следования символов в таблице ASCII).
```js
const array = [23, 11, 5, 16, 98, 55]
array.sort() // -> 11, 16, 23, 5, 55, 98
// sort(функция_сортировки)
const mySort = (a, b) => a - b
array.sort(mySort) // -> 5, 11, 16, 23, 55, 98
```
#### Работа с началом массива
* `shift()` – извлекает и возвращает первый элемент массива. Исходный массив также смещается (остается без первого элемента).
```js
const array = ['1st', '2nd', '3rd']
array.shift() // -> '1st'
array // -> ['2nd', '3rd']
```
* `unshift()` – добавляет элементы в начало массива со смещением. Возвращает новую длину массива.
```js
const array = ['3rd', '4th', '5th', 'last']
array.unshift('1st', '2nd') // -> 6
array // -> ['1st', '2nd', '3rd', '4th', '5th', 'last']
```
#### Работа с концом массива
* `pop()` – извлекает и возвращает последний элемент массива. Исходный массив также изменяется (остается без последнего элемента).
```js
const array = [10, 'JavaScript', 101]
array.pop() // -> 101
array // -> [10, 'JavaScript']
```
* `push()` – добавляет элементы в конец массива. Возвращает новую длину массива.
```js
const array = ['Ecma']
array.push('Script', 2015) // -> 3
array.join() // -> 'Ecma,Script,2015'
```
#### Поиск элементов массива
* `indexOf(searchElement, fromIndex)` – возвращает индекс первого найденного элемента, соответствующего `searchElement`.
```js
const drinks = ['water', 'tea', 'coffee', 'cacao']
const firstAppleIndex = drinks.indexOf('water') // -> 0
const secondAppleIndex = drinks.indexOf('water', 2); // -> 3
```
* `lastIndexOf(searchElement, fromIndex)` – возвращает индекс последнего найденного элемента, соответствующего `searchElement`.
```js
const vegetables = ['tomato', 'cucumber', 'carrot', 'eggplant']
const lastAppleIndex = vegetables.lastIndexOf('tomato') // -> 3
```
* `includes(searchElement, fromIndex)` – определяет, содержит ли массив `searchElement`.
```js
const fruits = ['apple', 'banana', 'orange']
const hasApple = fruits.includes('apple') // -> true
const hasMango = fruits.includes('mango') // -> false
```
* `find(callbackFn, thisArg)` – возвращает первый элемент, удовлетворяющий условию, заданному `callbackFn`.
```js
const numbers = [5, 12, 8, 130, 44]
const foundNumber = numbers.find(element => element > 10) // -> 12
```
* `findIndex(callbackFn, thisArg)` – возвращает индекс первого элемента, удовлетворяющего условию, заданному `callbackFn`.
```js
const numbers = [5, 12, 8, 130, 44]
const foundIndex = numbers.findIndex(element => element > 10) // -> 1
```
#### Итерация по элементам массива
* `forEach(callbackFn, thisArg)` – выполняет `callbackFn` для каждого элемента массива.
```js
const numbers = [1, 2, 3, 4]
numbers.forEach(element => console.log(element * 2)) // -> 2, 4, 6, 8
```
* `map(callbackFn, thisArg)` – создает новый массив с результатами вызова `callbackFn` для каждого элемента.
```js
const numbers = [1, 2, 3, 4]
const doubledNumbers = numbers.map(element => element * 2) // -> [2, 4, 6, 8]
```
#### Сведение массива к одному значению
* `reduce(callbackFn, initialValue)` – применяет `callbackFn` к аккумулятору и каждому элементу массива, чтобы получить одно значение.
```js
const numbers = [1, 2, 3, 4]
const sum = numbers.reduce((accumulator, element) => accumulator + element, 0) // -> 10
```
* `reduceRight()` – то же, что и `reduce()`, но применяет callback-функцию к элементам массива в обратном порядке (справа-налево).
```js
const numbers = [1, 2, 3, 4, 5]
// Вычисление факториала 5 (5! = 5 * 4 * 3 * 2 * 1)
const factorial = numbers.reduceRight((acc, number) => acc * number, 1)
console.log(factorial) // -> 120
```
В примере выше callback-функция умножает аккумулятор `acc` на каждый элемент массива, начиная с последнего элемента `5` и заканчивая первым `1`.
#### Преобразование массива
* `copyWithin()` – копирует часть элементов массива в другую позицию внутри того же массива, перезаписывая существующие элементы.
```js
// Копируем элементы с индекса 1 (включительно)
// начиная с позиции индекса 0
// до индекса 3 (не включительно)
[1,