/
Автор: Боссо Ю.
Теги: языки программирования компьютерные технологии программирование информационные технологии язык программирования java
ISBN: 978-5-17-174756-5
Год: 2025
Текст
IT
для начинающих
и опытных
JavaScript
Только самое нужное
Осваиваем самый популярный
язык программирования
Юбер Боссо / JackPotte
IT
для начинающих
и опытных
JavaScript
Только самое нужное
Осваиваем самый популярный
язык программирования
Юбер Боссо / JackPotte
Издательство ACT
Москва
УДК 004 43
ББК 32.973.26-018.2
Б85
Текущая, редактируемая версия книги «JavaScript» на английском языке
доступно в Wikibooks, коллекции учебников с открытым содержанием,
по адресу https://en.wikibooks.org/wiki/JavaScript.
Разрешается копировать, распространять и/или изменять этот
документ на условиях лицензии
Creative Commons Artribution-ShareAlike 3.0
(https://creativecommons.Org/hcenses/by-sa/3.0/1.
Боссо, Юбер (JackPotte).
Б85 JavaScript. Только самое нужное. Осваиваем самый популярный язык
программирования / Юбер Боссо (JackPotte), — Москва : Издательство
ACT, 2025. — 192 с.: ил. — (IT для начинающих и опытных).
ISBN 978-5-17-174756-5.
Перед вами краткое и емкое руководство по JavaScript, в котором соб-
рана только самая важная информация для быстрого освоения этого крайне
востребованного языка прог раммирования Здесь оассматоивэются ключевые
концепции, начиная с основ синтаксиса, работы с переменными, типами
данных и операторами и заканчивая продвинутыми темами, такими как
замыкания, асинхронное программирование, объектно-ориентированный
подход и модули.
Отдельное внимание уделяется практическим аспектам: работе с HTML,
обработке событий, манипуляциям с DOM, а также инструментам отладки
и оптимизации кода. Включены лучшие практики разработки, методы работы
с JSON и XML, взаимодействие с сервером, а также полезные советы для
эффективного кодинга.
Издание идеально подходит как для начинающих программистов, которые
хотят быстро ocBOHTbJavaScript, так и для опытных разработчиков, желающих
структурировать и обновить свои знания. Четкая структура, лаконичные
объяснения и практические примеры делают эту книгу удобным пособием
для самостоятельного изучения и повседневного исполвзовзния.
УДК 004.43
ББК 32.973.26-018.2
ISBN 978-5-17-174756-5
Перевод на русский язык: ООО «Интеджер».
Издание на русском языке: ООО «Издательство ACT».
Содержание
Введение.......................................................................11
Примечания...................................................................И
Динамические типы данных................................................11
Фун Ki тональное 11рограммиро вание.....................................11
Обьектно-ориснтированное программирование...............................11
Синтаксис, подобный С...................................................11
Отношение к Java....................................................... 12
] S-движки.............................................. - ............ 12
Ссылки................................................................... 12
Отношение к другим языкам......................................................13
Поведение переменных....................................................13
Область видимости переменных............................................13
Классы..................................................................14
Первая программа...............................................................15
Упражнения..................................................................15
JavaScript внутри HTML.........................................................17
Внутренний и внешний JavaScript.......................................... 17
Внешний JavaScript......................................................... 18
Атрибут src.................................................. .18
Атрибут type............................................................18
Атрибуты async и defer ............................................. .18
Расположение элементов <script>...................................... .18
Элемент <noscript>..........................................................19
JavaScript в XHTML-файлах..................................... .....19
Ссылки......................................................................20
Обработка событий..............................................................21
Второй пример...............................................................22
Инструменты разработки.........................................................23
Этап разработки....................................................... 23
Локально установленные инструменты......................................23
Онлайн..................................................................23
Валидация................................................................. 24
Оптимизация, обфускация.................................................24
Самопроверка...................................................................25
Введение....................................................................25
Синтаксис и семантика...................................................... 25
Преобразование типов (Type Conversion)..................................... 26
Циклы (Loops)...............................................................27
Полезные советы................................................................28
Предопределенные функции................................................ 28
alertO................................................................ 28
log()...................................................................28
4
Содержание
printO................................................................... 28
promptO....................................................................28
writeO................................................................... .28
Стиль написания кода...................................................... .29
Лексическая структура............................................................30
Сводка.......................................................................30
Чувствительность к регист ру.................................................30
Пробельные символы...........................................................30
Комментарии..................................................................31
Однострочные комментарии..................................................31
Мног осгрочные комментарии................................................31
Точки с запятой..............................................................31
Литералы.......... ................................................ 32
Идентификаторы....................................................... 32
Примечания...................................................................33
Ссылки................................................................... 33
Автоматическая вставка точки с запятой (Automatic Semicolon Insertion, ASI).......34
Примеры............................................................ .,.34
См. также............................................................. .35
Зарезервированные слова....... .............................................. 36
Ссылки........................................................... .36
Переменные.......................................................................37
Цель.........................................................................37
Объявление и инициализация...................................................37
Ключевое слово let..................................................... 38
Ключевое слово const......................................................38
Ключевое слово var............................................... .38
Пропуск объявления................................... . ............39
Типы данных... .............................................. 39
Область видимости (Scope)....................................................39
Блочная область видимости (Block Scope)...................................40
Функциональная область видимости (Function Scope).........................41
Модульная область видимости (Module Scope)................................41
Глобальная область видимости (Global Scope)...............................41
Ссылки.................................................................... 42
Типы данных..,...................................................................43
Введение.....................................................................43
Категории типов данных.......................................................43
Ссылки................................................................... 43
Примитивные типы данных..........................................................44
Строка (String)............................................................. 44
Свойства и методы для строк................................................. 45
length................................................................ 45
concat(text)..............................................................45
tndexOf(searchText).......................................................45
lastlndexOfl searchText)..................................................45
replaceftext. newtext)....................................................45
slice(start [, end])..................................................... 45
substr(start L number of characters]).....................................46
substringlstart [, end])..................................................46
Содержание 5
toLowerCaseO................................................................4b
toUpperCaseO............................................................ 46
Число (Number).................................................................46
Свойства и методы для чисел................................. ...... ...... .47
Свойства....................................................................48
Math.ceil(number)...........................................................48
Math.fl.>or(number).........................................................48
Math.round(number)..........................................................48
Math.max(number_l, number, 2)...............................................48
Math.min(number_l, number,2).................................... .48
Math.randomO................................................................48
Number.parselnt(strmg) и Number.parsefloat(string)...........................49
Biglm......................................................................... 19
Boolean...................................................................... 49
Undefined...................................................................... 49
Null........................................................................... 50
Symbol.........................................................................50
См. также..................................................................... 50
Ссылки.........................................................................50
Объекты............................................................................51
Создание объект а............................................................. 51
«Литеральная нотация» с использованием фтиурных скобок {}................... 51
Конструктор. ... ...... 51
ObjecLcreateO...............................................................52
Чтение свойства................................................................52
Добавление или изменение свойства_________________________________________ 52
Удаление свойс гва............................................................. 53
Объединение объектов______________________ ___________ .... _______ ____________53
Функции/методы как часть объекта............................................ 54
Массивы........................................................................... 55
Создание массива...............................................................55
Доступ к элементам массива.....................................................56
Различные типы дан вых.........................................................56
Вложенные массивы......................................................... 56
Свойства и методы..............................................................57
length......................................................................57
concat......................................................................57
join и split............................................................... 57
push........................................................................57
pop.........................................................................58
unshift.....................................................................58
shift.......................................................................58
См. также......................................................... 58
Даты...............................................................................59
Конструктор.................................................................. 59
Методы.........................................................................59
Статические методы..........................................................59
Методы экземпляра...........................................................60
«Как целое число»...........................................................60
Временные зоны................................................... 60
Новый API: Temporal ............................................. .61
См. также ............................................................... 61
б
Содержание
Регулярные выражения..............................................................62
Метод для строки match........................................................62
Принятие решений.......................................................... 62
Метасимволы.............................................................. 63
Подстановочный знак.................................................. 63
Квантификаторы ............................................................63
Модификаторы............................................................ 63
Классы символов............................................................64
Метод для строки replace......................................................64
Внешние ссылки....................................................... 64
Операторы.........................................................................65
Конкатенация строк.......................................................... 65
Арифметические операторы......................................................65
Побитовые операторы...........................................................6Ь
Операторы присваивания........................................................66
Операторы инкремента и декремента.............................................67
Пре- и пост-инкрементные операторы..................................... 67
Операторы сравнения...........................................................68
Логические операторы..................................................... 69
Другие операторы............................................................. 70
?:.........................................................................70
delete.....................................................................71
new...................................................................... 71
instanceof.................................................................71
lypeof................................................................. 72
См. также.............................................................. 72
Управляющие структуры............................................................ 73
if/else.......................................................................73
switch ........................... . ..............................75
try / catch / finally.................................................... 76
throw...... ...................................................... 77
Циклы.........................................................................77
См. также.....................................................................77
Циклы.............................................................................78
for (;;){} 78
Необязательные части синтаксиса........................................... 78
Вложенность................................................................79
continue / break.......................................................... 79
do {} while 0.................................................................80
while 0 {}................................................................. 80
for (x in Object) {}..........................................................80
for (x of Array) {} .................................. .. ... ......... 81
for..in vs. for..of......................................................... .81
Метод Object.entriesO........................................................ 81
Метод Array.forEachO...................................................... 82
См. также.................................................................... 83
Функции...........................................................................84
Объявление....................................... ... __________. 84
Вызов....................................................................... 85
Поднятие (Hoisting). ..................................................... 85
Содержание 7
Немедленно вызываемая функция (immediately Invoked Function)............... 86
Аргументы.................................................................... 86
Передача по значению (Call-by-value)..................................... 86
Значения по умолчанию................................................... 88
Переменное количество аргументов.......................................... 88
Возврат (return)..............................................................90
Стрелочные функции (=>).................................................... 90
Рекурсивные вызовы............................................................91
См. также.....................................................................92
Замыкания (Closures)..............................................................93
Лексическое окружение (Lexical environment)...................................93
Замыкание (Closure)...........................................................93
См. также.....................................................................94
Асинхронность (async).............................................................95
Однопоточность................................................................95
Строго последовательно? Нет.............................................. 96
Callback..................................................................... 97
Промис (Promise)............................................................ 98
async/await...................................................................99
Реалистичный пример-....................................................... 100
См. также....................................................................101
Ссылки............................................................. 101
Объектно-ориентированное программирование..................................... 102
Классовый подход в ООП.......................................................102
Прототипный подход в ООП .. ................................................. 102
ООП в JavaScript. «Два пиджака на одно тело».................................102
Классический синтаксис....................................................103
Синтаксис «классов»..........................................................105
См. также.................................................................... 105
Классическое ООН.................................................................106
Конструкция..................................................................106
Функции...................................................................107
new...................................................................... 107
Предопределенные типы данных............................................. 108
Наследование.................................................................108
setPrototypeOf............................................................ 108
new...................................................................... 109
Object.create.............................................................110
Отличие от подходов, основанных на классах.............................. 110
Проверка иерархии объектов.................................................. 111
getPrototypeOf............................................................Ill
insranceof................................................................112
typeof....................................................................112
См. также.................................................................. 112
Классы в ООП.................................................................... ИЗ
Создание ................................................................ ИЗ
Статические свойства и методы..............................................ИЗ
Get.......................................................................114
Наследование................................................................ 114
Управление доступом .........................................................115
8
Содержание
Полиморфизм............................................ ................ 116
this......................................................................117
См. также.......... 117
Модули.......................................................................118
Без модулей...............................................................118
Модули ECMAScnpt (FS модули)..............................................119
Модули Node.js (CommonJS).................................................120
См. также.............................................................. 121
Генераторы....................................................................122
Примеры...................................................................122
Параметры.................................................................123
Ссылки..... ............................................................ 123
Введение н Document Object Model (DOM).......................................124
Узлы.................................................................. 124
Доступ к узлам............................................................124
Доступ к содержимому......................................................125
Изменение содержимого................................................ 125
Изменение структуры дерева................................................126
См. также.................................................................126
Поиск элементов ..............................................................127
Испо.гьзование ID................................................... 128
Использовашсе имени тега................................................ 128
Использование имени класса................................................129
Использование селектора запросов......................................... 129
Навигация по дереву DOM.................................................... 130
См. также.................................................................130
Изменение элементов..........................................................131
Пример страницы...........................................................131
Изменение содержимого... ................................................131
Изменение атрибута........................................................132
setAttributef)........................................................133
См. также.................................................................133
Добавление элементов.........................................................134
Создание элементов ...................................................... 134
Создание атрибутов........................................................135
Альтернативный синтаксис..............................................136
Соединение частей.........................................................136
«Неправильное» использование innerHTML....................................136
writeO................................................................. 136
См. также................................................................ 137
Удаление элементов...........................................................138
Удаление элементов........................................................138
Дочерние эл ементы дочерних элементов.................................138
Свойство parentNode...................................................138
Удаление атрибутов...................................................... 139
См. также.................................................................139
Реструктуризация DOM.......................................................... 140
Пример страницы...........................................................140
Перемещение элемента в конец списка соседей (дочерних элементов одного уровня).140
Содержание
9
Перемещение элемента перед соседом (дочерним элементом одного уровня).......141
Атрибуты....................................................................141
См. также ...................................................................142
Изменение стилей элементов.....................................................143
Пример..................................................................... 143
Свойства style............................................................. 144
См. также...................................................................144
Обработка событии DOM.......................................................... 145
Создание и вызов событий....................................................145
Встроенные в HTML.......................................................145
Программно в JavaScript............................................ 146
Типы событий................................................................147
Свойства событий............................................................150
removeEventListener.........................................................151
Синтетические события.................................................... 152
(А)синхронное поведение......................................................153
См. также...................................................................154
Ссылки......................................................................154
Отладка JavaScript.............................................................155
Отладчики JavaScript........................................................ 155
Firebug.................................................................155
Venkman JavaScript Debugger.............................................155
Отладка в Internet Explorer............................................ 155
Отладка в Safari........................................................156
11Г- Ферма модульного тестирования JavaScript ................... . 156
jsUnit 156
Встроенные инструменты отладки...........................................157
Распространенные ошибки.....................................................157
Методы отладки..............................................................158
Отслеживание переменных во время выполнения скрипта.....................158
Ошибки браузеров............................................................158
Код, зависящий от браузера..................................................159
Дополнительная .литература..................................................159
Ссылки......................................................................159
Оптимизация.................................................................... 160
Оптимизация JavaScript......................................................1G0
Техники оптимизации.....................................................160
Распространенные ошибки и заблуждения........................................ 160
Конкатенация строк......................................................160
Shell..........................................................................163
Автономная оболочка (Standalone).......................................... 1G3
В браузере..................................................................163
Внешние ссылки........................................... 164
Формы..........................................................................165
Ссылки................................................. 165
Букмарклеты (Bookmarklets)....................................................-167
Схема URI JavaScript.........................................................167
Примеры использования................................................ 167
Управление медиа........................................................ 167
10
Содержание
Зациклить видео...... ........................ .................167
Перейти к десяти минутам (с использованием умножения)..................167
Перейти вперед на одну минуту (шестьдесят секунд)......................167
Перейти назад на полминуты (с использованием деления)..................167
Получить продолжительность виде-i на странице в консоли................167
Вывести текущее время воспроизведения..................................168
Установить громкость звука на 50%......................................168
Отключить звук........................................................ 168
Удвоить скорость воспроизведения.......................................168
Запросить скорость воспроизведения.....................................168
Запросить позицию воспроизведения в секундах...........................168
Запросить позицию воспроизведения в минутах............................168
Запросить позицию воспроизведения в процентах (от 0 до 100)............168
Использование нескольких строк кода........................................168
Протокол JavaScript в ссылках..............................................169
Примеры....................................................................169
Работа с файлами.............................................................. 170
Ссылки.................................................................. 170
Обработка XML.................................................................172
Простая функция для открытия XMI.-файла....................................172
Использование..............................................................172
Обработка JSON................................................................173
Нативная поддержка JSON....................................................173
Старый способ..........................................................173
]SONP. . . 173
Дополнительная информация................................................. 174
CS Communication..............................................................175
XMLHttpRequest.............................................................175
Ajax.......................................................................176
Библиотеки.................................................................176
Fetch API..................................................................177
Ссылки.....................................................................177
Глоссарий.....................................................................178
Полезные инструменты для программистов на JavaScript..........................181
Редакторы / IDE........................................................181
Движки и другие инструменты__________________________________ .182
Лучшие практики................................................................ 183
document, write............................................................183
J avaScript -протокол......................................................183
Валидация email.............................................................J 84
Тестовая страница......................................................183
use strict.................................................................189
Для дальнейшего чтения.....................................................189
Ссылки.....................................................................190
Введение
Примечания
JS (JavaScript) — это язык программирования, который реализует международный
стандарт ECMAScript. Он основан на следующих концепциях.
Динамические типы данных
JS поддерживает несколько примитивных типов данных (Number, String.
Boolean, Biqlnt, Symbol, Undefined, Null) и различные производные типа object
(Array, Date, Error, Function, RegExp)111121. Если переменная существует, ее тип чет-
ко определен. Однако тип может быть изменен в любой момент путем присваива-
ния значения другого типа. Например, фрапиеит кода let х; х = 'Some text1;
х = 2; х = [10, 11, 12]; абсолютно корректен. Он не вызовет ошибок на эта-
пе компиляции или выполнения. Только тип переменной х изменится с Undefined
на String, затем на Number и, наконец, на Object/Array.
(Примечашге: JSON это текстовый формат данных, а не тип данных. Как тако-
вой он не зависит от языка. Он использует синтаксис объектов JavaScript.)
Функциональное программирование
Функции являются объектами первого класса, подобно переменным. Они могут
быть присвоены переменным, переданы в качестве ар1ументов другим функциям
или возвращены из функций. Фрагмент кода function sayHello() {return 'Good
morning }; let x = sayHello; console.log(x()); создает функциюsayHello,
присваивает ее переменной х и выполняет ее, вызывая х ().
Объектно-ориентированное программирование
JS поддерживает объектно-ориентированное программиро-
вание (ООН) и наследование через прототипы. Прототип — это
объект, который может быть клонирован и расширен. При этом
возникает цепочка прототипов (ht1ps://developer.inozilla.org/en-US/
docs/Lea m/JavaScript/Obj ects/Obj ect_ prot otypes).
Это отличается от других 00-языков, например Java, где
для объектно-ориентированных возможностей, таких как насле-
дование (htrps://developer.mozilla.org/en-US/docsJ,earn/JavaScript/
Objects,'Object-oriented_programming), используются классы.
Тем не менее на синтаксическом уровне классы доступны в JS
Но это лишь «синтаксический сахар». «Под капотом» JS использует
механизм прототипов.
Синтаксис, подобный С
Синтаксис JS очень похож на синтаксис С, Java или других языков семейства С. Од-
нако всегда следует учитывать, что его концепции и поведение во время выполне-
ния программ существенно отличаются.
12
t-ведение
Отношение к Java
JS не имеет отношения к Java, за исключением схожего синтаксиса Чтобы избе-
жать возможной путаницы, мы хотим четко определить некоторые различия между
JS и Java.
Вначале Netscape разработала JavaScript, a Sun Microsystems — Java. Java включа-
ет классы и экземпляры объектов, тогда как JavaScript использует прототипы. В Java
переменные должны быть объявлены перед использованием, что не обязательно (hi
не рекомендуется) в JS.
В Java переменные имеют неизменяемый статический тип (например, int
или String), который остается неизменным на протяжении всею времени выполне-
ния программы. В JS переменные также имеют тип (например, Number или String),
но этот тип может изменяться во время выполнения программы. Тип определяется
из окружения. Поэтому нет необходимости и возможности явно определять тип:
int х = 0; // Java: 'имя типа', 'имя переменной', ...
let х = 0; // JS: 'let' или 'const', 'имя переменней’, ...
// Тип будет Number' из-за правой части знака равенства.
let х = String(0); // о5:явное изменение с Number' на String' ПЕРЕД присваиванием х
// Тип будет String'. Проверьте это с помощью. alert(typeof х)
JS-движки
JS может выполняться как на стороне клиента, так и на стороне сервера. Первые
версии JS выполнялись в браузерах, которые выступали в роли интерпретаторов. Се-
годня язык обрабатывается компиляторами Just In Time (J1T). Они анализируют скрипт,
создают абстрактное синтаксическое дерево (Abstract Syntax Tree, AST), оптимизиру-
ют дерево, генерируют байт-код, специфичный для JIT, создают машинный код, спец-
ифичный для оборудования, из байт-кода и выполняют машинный код. Такие JIT-
компиляторы существуют не только в браузерах. Они также могут быть частью других
приложений, например node.js, который написан преимуществешю на C++.
Широко используемые JS-движки:
• V8 от Gougle: Google Chrome, Electron, Chromium, node.js
• SpiderMonkey от Mozilla. Firefox
• JavaScriptCore от Apple, Safari
• Actionscript от Adobe, Flash
Ссылки
1. MDN: Типы данных
(https://developer.
mozilla.org/en-US/
docs/Web/JavaScript/
Language_Overview)
2. MDN: Подробнее
о типах данных
(hrtps://developer.
mozilla.org/en-US/docs/
Web/JavaScri p t/Data_
structures)
Отношение к другим языкам
Если у вас есть опыт программирования или вы обучались другому языку, изучение
JS будет одновременно и проще, и сложнее. Особенно тот факт, что JS является членом
семейства языков С (С, C++, Java,...), может одновременно помогать и сбивать с толку.
Он использует общий синтаксис, но реализует концепции, которые отличаются от кон-
цепций других членов семейства. Поэтому он может соблазнить вас своим синтакси-
сом, похожим на С или Java. Однако «под капотом» это совершенно другой «зверь». Се-
мантика и дизайн языка вдохновлены языками программирования Self и Scheme.
Для программистов на С или Java легкой частью будет освоение синтаксиса. Боль-
шинство элементов управления потоком, логики и арифметики одинаковы. Однако,
глубже погрузившись в язык, вы заметите различия. Вот некоторые отличия от Java
Поведение переменных
Начнем с очевидного; JS — это слабо типизированный язык, что влечет за собой
некоторые последствия:
• Целые числа и числа с плавающей точкой представлены 64-битными числами
с плавающей точкой (но, что удивительно, побитовые операции все еще
доступны, и иногда даже осуществляются быстрее).
• Вы можете изменять тип переменной по своему7 усмотрению.
• Объекты состоят из пар «ключ/значение», называемых свойствами. Значения
можно изменять, а свойства можно добавлять или удалять из объекта
по желанию.
Список можно продолжать, и нам предоставлены широкие возможности делать
как замечательные, так и порой невероятно глупые вещи в процессе программиро
вания. Поэтому очень важно сохранять ясный ум, пытаясь использовать силу дина-
мических переменных.
Область видимости переменных
• От модуля к модулю
В Java ключевые слова public, private и protected определяют видимость
переменных для других модулей (классов). В JS существует только простой ме-
ханизм export/import или module.exports/require.
• Внутри модуля
В JS видимость внутри модуля определяется ключевыми словами var (уста-
ревшее, не используйте его), let и const. В Java также существует ключевое
слово var, но его семантика немного отличается. JS-конструкция const экви-
валентна final в Java.
• Внутри блоков
Блоки — это последовательности кода, окруженные фигурными скобками
{ } Видимость переменных в блоках идентична в JS (при использовании let
14
Отношение к другим языкам
или const) и Java переменные видны внутри определяющего блока и вло-
женных блоков, но не за пределами определяющего блока.
* Замыкания
Замыкание (closure) — это анонимная или именованная функция, которая мо-
жет ссылаться на переменные своей внешней области видимости. В этом слу-
чае функция «видит» значение переменной на момент создания функции,
но не на момент ее вызова. JS использует эту концепцию с самого начала. Java
использует похожие, но не идентичные техники для доступа к переменным
внешнего контекста: внутренние классы и лямбда-выражения.
Классы
В отличие от Java, JS — это язык без классов. Вместо этого JS использует прототи-
пы для реализации объектно ориентированных во сложностей, таких как наследова-
ние. Классы могут быть смоделированы, но это лишь «синтаксический сахар», и если
вы выбросите идею классов из головы, процесс обучения станет проще.
Первая программа
Вот простое выражение на JavaScript, которое создает всплывающее окно с тек-
стом "Hello World1":
alert("Hello World!");
Чтобы браузер выполнил это выражение, его необходимо поместить внутрь
НТМI.-элемента <script>.3TOT элемент указывает, какая часть HTML-кода содержит
исполняемый код. Он будет описан более подробно позже:
<script>
alert("Hello World!");
</script>
Элемент <script> должен быть вложен внутр], элемента <head> HTML-докумен-
та. Если страница открыта в браузере, который поддерживает JS, браузер выполнит
(исполнит) это выражение вь время загрузки страницы:
<1 DOCTYPE html>
<html lang-'en >
<head>
<title>Soire Page</title>
<script>
alert("Hello World! );
</script>
</head>
<body>
<p>The content of the web page </p>
</body>
</html=
Эта простенькая программа Hello World' может быть использована как от-
правная точка для любого нового проекта, который вам нужно создать.
Упражнения
1. Скопируйте и вставьте простую программу’ в файл и сохраните его
на жестком диске как exercise_1 -1 .html. Вы можете запустить его разными
способами-
• Перейдя к файлу через файловый менеджер и открыв его с помощью браузера.
• Запустив браузер и открыв файл через меню.
• Запустив браузер и указав URL-адрес к exercise_1-1. html с использованием
протокола file. Обратите внимание, что: а) после file: должно быть три слеша
и б) замените temp на имя вашей директории:
с Windows: file:///С:/temp/exercise_1 -1 .html (синтаксис Windows,
но используйте слеш вместо обратного слеша)
с Linux: file:///temp/exercise_1 -1 .html
Что произойдет?
Решение: появится диалоговое окно с текстом: Hello Wo rid !
16
Первая программа
2. Сохраните указанный выше файл как exercise_l-2.html. Замените
двойные кавычки в строке alert( "Hello World!"): на одинарные, чтобы
она выглядела как ale rt (' Hello World! );, и сохраните результат. Если вы
откроете этот файл в браузере, что произойдет?
Решение: ничего не изменится. Появится диалоговое окно с текстом;
Hello World! Двойные кавычки и одинарные кавычки (апострофы) идентичны в JS.
JavaScript внутри HTML
Язык JavaScript изначально был создан для выполнения в браузерах и обработки
динамических аспектов пользовательских интерфейсов, таких как проверка ввода
пользователя, изменение содержимого страницы (DOM) или внешнего вида интер-
фейса (CSS), а также обработка событий. Это подразумевает, что должна существовать
точка соединения между HTML и JS. Эту роль выполняет HTML-элемент <script>.
Это обычный HTML-элемент, содержимое которого представляет собой JS.
Элемент <script> может находиться практически в любом месте HTML-файла,
как внутри <head>, так и внутри <body> Существует лишь несколько критериев
для выбора оптимального места.
Внутренний и внешний JavaScript
Элемент <script> либ«> содержи! JS-код напрямую, либо ссылается на внешний
файл или URL. содержащий JS-код, с помощью атрибута src. Первый вариант назы-
вается внутренним JavaScript (Internal JavaScript) или встроенным JavaScript (Inline
JavaScript), а второй — внешним JavaScript (External JavaScript).
В случае внутреннего JavaScript элемент <sc ript* выглядит следующим образом:
<scripc>
// напишите ваш JS-код напрямую здесь. (Эта строка - комментарий в синтаксисе JS)
alert(“Hello World' ') ;
</script>
Внутренний JavaScript имеет преимущество в том, что и HTML, и JS находятся в од-
ном файле, а это удобно для быстрой разработки. Это часто используется для вре-
менного тестирования идей, а также в ситуациях, когда код скрипта небольшой
или специфичен для одной страницы.
Для внешнего JavaScript элемент <script> выглядит так:
<!-- укажите файл или URL, где находится код. (Эта строка - комментарий в синтаксисе HTML)
-->
«script src= 'myScript.js">«/script>
«script src= https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.
js "></script>
<!-- хотя внугри элемента script ничего нет, следует учитывать, что спецификация HTML5 -->
<!— не позволяет сокращать элемент script Д( «script src="myScnpt.js" /> -->
Размещение JS в отдельном файле рекомендуется для объемных программ, осо-
бенно тех, которые используются на нескольких страницах. Кроме того, такое разде-
ление поддерживает принцип разделения ответственности (Separation of Concerns):
один специалист работает над HTML, а другой — над JS. Также это способствует раз-
делению содержимого страницы (HTML) и ее поведения (JS).
В целом использование внешнего JavaScript считается лучшей практикой в разра-
ботке программного обеспечения.
18
JavaScript внутри HTML
Внешний JavaScript
Для получения более подробной информации вы можете обратиться к MDN1’1.
Атрибут src
Добавление src="myScript js" к открывающему тегу <script> означает,
что JS-код будет находиться в файле с именем mySc гipt. j s в той же директории (пап-
ке), что и HTML-файл. Если JS-файл находится в другом месте, необходимо изменить
атрибут src на соответствующий путь. Например, если он находится в поддиректории
с именем js, путь будет выглядеть так: src="js/myScript. js".
Атрибут type
JavaScript — не единственный язык для веб-разработки, но он является наиболее
раснространешзым на стороне клиетгга (РНР работает на стороне сервера). Поэтому
он считается типом кода по умолчанию для HTML5. Формальная запись для типа:
type= 'text/javascript". Ьолее старые версии HTML «знают» множество дру-
гих типов скриптов В настоящее время все они считаются устаревшими. Некото-
рые примеры: application/javascript, text/javascript).5. text/jscript
или text/livescript.
В HTML5 спецификация гласит, что если вы используете JS, атрибут type должен
быть опущен в элементе <sc ript>!11, как для внутреннего, так и для внешнего напи-
сания кода:
<!-- В настоящее время атрибут туре не требуется
<script type="text/]avascript >.. .</script>
<! — Код HTML5 -->
<script>...</scri pt>
Атрибуты async и defer
Старые браузеры используют только один или два потока для чтения и анали-
за HTML, JS, CSS и т. д. Эго может привести к плохому пользовательскому опыту (UX)
из-за времени задержки при последовательной загрузке HTML, JS, CSS, изображений
и пр. Когда страница загружается впервые, у пользователя может сложиться впечат-
ление, что система медленная.
Современные браузеры могут выполнять множество задач параллельно. Чтобы
инициировать это параллельное выполнение в отношении загрузки и выполнения
JS, элемент <script> может быть расширен двумя атрибутами: async и defer.
Атрибут async приводит к асинхронной загрузке скрипта (параллельно с други-
ми задачами) и его выполнению, как только он станет доступен:
<script async src="myScript.js“></script>
Атрибут defer действует аналогично. Он отличается от a sync тем, что его выпол-
нение откладывается до полного анализа страницы:
«script defer src-"myScript. js "></script>
Расположение элементов <script>
Элемент <script> может находиться практически в любом месте HTML-файла.
Однако существуют некоторые лучшие практики для ускорения загрузки сайта131. Не-
Элемент «noscript
19
которые рекомендуют размещать его непосредственно перед закрывающим тегом
</body>. Это ускоряет загрузку а также позволяет напрямую манипулировать объ-
ектной моделью документа (Document Object Model, DOM) во время ее отображения.
Но аналогичного поведения можно добиться с помощью описанных выше атрибутов
async и defer:
<!DOCTYPE html?
«html?
«head?
«title?Example page«/title>
«/head?
«body?
<!-- HTML-код здесь -->
«script src="myScript.js“>«/script>
«/body?
</html>
Элемент <noscript>
Может случиться так, что пользователи отключили JS в своих браузерах по сооб-
ражениям безопасности или другим причинам. Или они используют очень старые
браузеры, которые вообще не могут выполнять JS. Чтобы проинформировать пользо-
вателей в таких случаях. существует элемент «noscript?. Он содержит текст, кото-
рый будет показан в браузере Текст должен объяснят],, что JS-код не будет выполнен:
«’DOCTYPE html?
<html>
<head>
«title?Example page«/title?
«script?
alert("Hell< World!");
«/script?
«noscript?
alert(’'Sorry, the JavaScript part of this page will not be executed because
JavaScript is not running in your browser. Is JavaScript intentionally deactivated?");
«/noscript?
«/head?
«body?
<!-- HTML-код здесь --?
«/body?
«/html?
JavaScript в XHTML-файлах
XHTML использует более строгий синтаксис, чем HTML. Это приводит к неболь-
шим различиям.
Во-первых, для внутреннего JavaScript необходимо, чтобы скрипты были введены
и завершены двумя дополнительными строками, как показано в следующем примере,
«script?
// «'[CDATA[
alert("Hello World!");
И ]]>
«/script?
Во-вторых, для внешнего JavaScript атрибут type обязателен.
20
JavaScript внутри HTML
Ссылки
1. MDN: Элемент script
(https :/7developer.mozilla.
org/en-US/docs/W eb,'HTML/
Element/script)
2. WHATWG; Атрибут type
(https://html.spec.whatwg.
org/ dev/s crip ting.h t ml#att r-
sc.ript-type)
3. Yahoo. Лучшие практи-
ки для ускорения вашего
сайта
(http://developer.yahoo.
com/performance/rules.
html)
Обработка событий
До сих пор представленные JS-программы запускались автоматически при загруз-
ке HTML-страницы. Это делало все компактным, простым и понятным.
Теперь мы хотим представить механизм запуска программы ь определенные мо-
менты времени. Когда пользователь вводит какие-либо данные, может потребовать-
ся их проверка; когда пользователь нажимает кнопку, может потребоваться запуск
сложного действия, например, запроса к базе данных. Действия (проверка, запрос
к БД) будут обрабатываться в JS-функции, а некоторый HTML-код будет иницииро-
вать вызов таких JS-функций. Чтобы понять, как это работает, необходимо изучить
события. В данной главе мы подробно остановимся на их изучении.
Предположим, пользователь нажимает на кнопку. Это генерирует событие
one lick. Возникновение такого события декларативно связывается с вызовом име-
нованной JS-функции. Браузер вызывает эту JS-функцию, и она выполняется.
Полный код HTML с встроенным JS выглядит следующим образом:
<1 DOCTYPE htffll*
<html>
<head=>
<title>Testing an event</title>
<script>
function showSomething() {
alert('Someone clicked the button. );
}
«/script*
</head>
«body*
<h1>Click the button«/h1>
«button type="button" onclick=,showSomething()">A button«/button>
«/body*
</html>
• В отличие от предыдущих примеров, зтри загрузке страницы ничего
не происходит. Это связано с тем, что команда alert () встроена в JS-функцию
showSomething (). Эта функция только определена, но не запущена.
• HTML-элемент <button> имеет атрибут onclick со значением
showSomething().
• Когда кнопка нажимается, происходит событие onclick. Событие привязано
к кнопке
• Браузер обрабатывает событие и замечает, что должна быть запушена функция
с указанным именем.
• Браузер ищет функцию во всех доступных JS-скриптах (обратите внимание,
что имя, как и весь JS-код, чувствительно к регистру!).
• После нахождения функции с точно таким именем в части
«script*.. .</script* браузер запускает ее.
• Функция выполняется и показывает сообщение.
По суги, JS-функция с ее поведением отображения сообщения будет запускаться
каждый раз, когда пользователь нажимает на кнопку.
22
Обработка событий
Второй пример
Этот пример предлагает возможность изменить цвет фона некоторых HTML-эле-
ментов, Он использует три кнопки, две JS-функции и один тип события (onclick: су-
ществует множество других типов). Кроме того, он вводит концепцию идентифика-
тора элемента (id):
<’DOCTYPE html>
<html>
«head*
<title*Second test for events«/title*
«script*
function makeGreen() {
document getElementById("mainPart")
.style background = green",
}
function makeBlue() {
document getElementBy!d(’mainPart")
style background = "blue";
document.getElementBy!d("blueButton")
.style background = aqua ,
}
</script>
«/head*
<body id="mainPart">
<h1*Click the buttors«/h1>
«button type="button" onclick=”makeGreen()">GREEN«/button>
«button type='button" onclick=‘"makeulue()" id-'blueButtoc"*BLUE</button>
«button type="butt on">Nothing</button*
«/body*
</html>
Чем этот пример отличается от первого?
• Есть три кнопки. Первые две связаны с JS-функцией: третья — нет.
• Элементы <body> и <button> содержат атрибут id="...Это присваивает
им идентификатор, который может быть использован в JS для их поиска
• Элемент <script> содержит две функции с разными именами.
• Когда вы нажимаете на одну из кнопок, вызывается связанная JS-функция.
Поскольку третья кнопка не связана с JS-функцией, ничего не происходит.
• В JS часть кода document. getElementBy!d("...") находит элемент с этим
ID. Часть кода . style . background = изменяет цвет фона этого
элемента. Обратите внимание, что две части написаны на отдельных строках
только для удобства чтения исходного кода на небольших устройствах.
Вы можете объединить их в одну строку.
• Функция makeBlue() выполняет два оператора и изменяет цвет фона тела
сзраницы и самой кнопки
Инструменты разработки
При работе с JavaScript (или HTML, CSS,...) необходимы инструменты для обработ-
ки исходного кода и повышения производительности. Во-первых, существуют инстру-
менты, помогающие разрабатывать исходный код. Во-вторых, код может быть про-
верен на соответствие синтаксическим правилам. Далее, код может быть «приведен
в порядок» (отступы, переносы строк, пустые строки и т. д.). И, наконец, код может быть
оптимизирован — с точки зрения размера, производительности или шифрования.
Этап разработки
Локально установленные инструменты
Самый простой способ написания кода — использование простого текстового ре-
дактора, такого как Noiepad++, Vim или Gnome gedit (или Gnome Text Editor). Создай-
те директорию, в которой будут находиться все файлы вашего проекта, например,
. . /firstProject. Там вы можете создать файлы, например, excercise_1 .1 .btml
Начните работу с файлами, как описано в главе «Первая программа». Результат мож-
но будет увидеть в браузере.
У этого подхода есть свои плюсы и минусы. Инструменты легко установить,
и они имеют простой пользовательский интерфейс. Однако они не предоставляют
помощь; они просто содержат текст, который вы пишете. Иногда они поддерживают
подсветку синтаксиса или автоматическое форматирование отступов, но чаще всего
не дают подсказок по синтаксическим ошибкам. Пользователь вынужден знать син-
таксис языка, с которым он работает. Мы считаем, что этот подход хорошо подходит
для начинающих: они должны выполнять свои упражнения на низком уровне.
На следующем уровне можно использовать более сложные инструменты, напри-
мер Visual Studio Code. В дополнение к обработке текста они предлагают дополни-
тельные функции, начиная от подсветки синтаксиса и заканчивая отладкой или об-
ширной поддержкой для команд разработчиков.
Онлайн
В качестве альтернативы локально установленным инструментам можно рабо-
тать с онлайн-инстру ментами для JavaScript, например:
JSFiddle
(https://j sfiddle .net/)
W3Schools
(https://www.
w3schools.com/js/tryit.
asp?filename=ti7js_default)
PlayCode
(htt ps://pl aycode.io/
javascript)
24
Инструменты разработки
Обычно они предлагают интегрированную среду для HTML, CSS и JS, включая
предварительный просмотр в браузере и доступ к консоли браузера.
Валидация
Вероятно, на первом этапе ваш код будет содержать синтаксические ошибки, на-
пример f0 г вместо for. Браузеры довольно «снисходительны» и стараются самосто-
ятельно исправить или игнорировать простые ошибки. Конечно, весь исходный код
должен соответствовать заданным синз аксическим правилам. Но поскольку браузе-
ры предоставляют ограниченные возможности для проверки или поиска ошибоч-
ных строк, необходимо использовать специальный инструмент для поиска и объяс-
нения синтаксических ошибок.
Такие валидаторы иногда предлагают не только проверку, но и дополнительные
функции, такие как форматирование или предварительный просмотр, например:
JS validator
(https://
javascriptvalidator,
net/)
JS + HTML validator
(https:/'www.
htinlstrip.com/
j a vascript -va hdat or)
W3C validator for
HTML
(htips://validator.
w3 org/#validate_
hyjnput)
FreeFormatter
(https://www.
freeformatter.com/
h tml- vali dat or.ht ml)
Оптимизация, обфускация
Время, необходимое для передачи HTML- и JS-кода с сервера на браузер, может
быть сокращено путем удаления всех ненужных пробелов, новых строк, табуля-
ций и т. д.
Когда JS-код загружается в браузер, его легко может просмотреть пользователь.
Если вы хотите скрыть исходный код, можно использовать технику обфускапии.
Она преобразует исходный код в более или менее нечитаемый для человека код.
Упомянутый ранее JS + HTML validator предлагает все эти техники.
Самопроверка
Вы можете проверить себя, ответив на следующие вопросы. Если возникают сомне-
ния, рекомендуется проверить код в вашей среде разработки (редакторе, IDE, браузере).
Это также проверка того, установлены ли у вас все необходимые инструменты для выпол-
нения примеров.
Введение
1. Внутри какого HTML-элемента размещается JavaScript-код?
□ <suurce>
О <scripting>
□ Ни один из перечисленных
2. Приведет ли эта последовательность операторов к ошибке?
let х = 0;
х = 1;
х = one' ;
□ Нет
Синтаксис и семантика
1. Есть ли синтаксическая ошибка в коде ниже?
let х = 1:
□ Да
□ Нет
2. Есть ли синтаксическая ошибка в коде ниже?
let х = 1; let у = 2, х+у - 3; □ Да П Нет
3. В какой строке содержится синтаксическая ошибка?
/* 1 */ let х = 1;
/* 2 */ let у = 1;
/* 3 */ let х = 1, у = 1;
/* 4 */ let х, у = 1;
Строка 1
□ Строка 2
□ Строка 3
□ Строка 4
□ Ни одна из перечисленных
4. В какой строке содержится синтаксическая ошибка?
/* 1 */ let firstName_1 = 'Michael''
/* 2 */ let firstName_2 = Michael'
/* 3 */ let firstName_4 = 'Mikhail'
/* 4 */ let firstNanie.5 = Михаил";
□ Строка 1
П Строка 2
□ Строка 3
[ | Строка 4
□ Ни одна из перечисленных
5. Какая строка приводит к сообщению об ошибке?
/* 1 */ let x = 1;
/* 2 */ const у = 2;
/* 3 */ x = 3;
/* 4 */ У = 4;
□ Строка 1
“1 Строка 2
□ Строка 3
□ Строка 4
□ Ни одна из перечисленных
26
Самопроверка
6’. Какая строка приводит к сообщению об ошибке?
/* 1 */ let x = 1; /* 2 */ x = 2 + 3(4 + 5); /* 3 */ x = 3; /* 4 */ x = -x; □ Строка 1 □ Строка 2 □ Строка 3 □ Строка 4 □ Ни одна из перечисленных
7. Какая строка приводит к сообщению об ошибке?
/* 1 */ let х = [1, 2]; /* 2 */ let х = [[1], [2]]; /* 3 */ let х = [[1, 2], [3, 4]]; /* 4 */ let х = [[[1], [2]], [[3], [4]]]; /* 5 */ let х = [1]. [2]; /* 6 */ let x = [1, '2 ]; □ Строка 1 □ Строка 2 □ Строка 3 □ Строка 4 П Строка 5 □ Строка В П Ни одна из перечисленных
8. Есть ли синтаксическая ошибка в коде ниже?
use strict'; let persons = [ Alice , Bert', 'Caesar']; for (let i = 0, i < persons.length, i++) { alert(persons[i]); □ Да □ Нет
} //
9. В какой строке содержится синтаксическая ошибка?
/* 1 */ alert("1 + 2 = " + 3); /* 2 */ alerr("1 + 2 = ” + "3"); /* 3 */ alert("1 + 2 = “ 3) /* 4 */ alert(1 + 2 == 3) □ Ciрока 1 □ Строка 2 П Строка 3 □ Строка 4 □ Ни одна из перечисленных
Преобразование типов (Type Conversion)
1. Какие сообщения не будут показаны?
let х = 1, у = 2, z = 2 ;
alert(x + у);
alert(x + z);
alert(х - z);
□ Все будут показаны
2. Какие сообщения не будут показаны?
let х = 1;
alert(x);
alert(x = 5);
alert(x -= '5');
alertfx === 5);
□ Сообщение об ошибке (Error Message)
□ true
□ false
□ 5
□ 1
Циклы (Loops)
27
Циклы (Loops)
1. Каким будет результат в переменной, sum?
"use strict*;
let sum = 9;
tor (let i=1; i < 5; i++) {
sum = sum + i;
} //
alert(sum);
Конечное значение переменной sum будет
2. Каким будет результат в переменной sum?
"use strict ;
let sum = P;
for (let 1 = 0; i < 5; i++) {
for (let j = 10; j >= 8; j--) {
if (i •” j) {
sum = sum + i - j + 1;
} //
} //
} //
alert(sum);
Конечное значение переменной sum будет
3. Есть ли синтаксическая ошибка?
"use strict";
let sum = 0;
for (let i = Э; i < 5; i++)
for (let j = 10, j >= 0; j--) {
if (i === j) {
sum = sum + i - j + 1;
} //
} //
} //
alert(sum);
4. Каким будет результат?
"use strict";
let sum = 0;
for (let i = 0; i = 3; i++) {
sum = sum + i;
) //
alert(sum);
□ Да
□ Нет
□ О
П«
□ Бесконечный цикл (Infinite loop)
□ Ни один из перечисленных вариантов
Полезные советы
Предопределенные функции
Во всем учебнике приведены примеры кода. Обычно результа-
ты выполнения программы проверяются в браузере. Это делает-
ся с помощью методов, которые соответствуют интерфейсам Web
API (https://deveJoper.mozilla urg/en-US/docs/Web/APl) и реализова-
ны в браузерах.
alert()
Функция alert () создает модальное окно, отображающее заданный текст,
let х = 5;
window.alert("The value of 'x' is: " + x); // явная нотация
alert("The value of ’ x* is: " + x); // краткая нотация
log()
Функция log () записывает сообщение в консоль браузера. Консоль — это окно
браузера, которое обычно не открыто. В большинстве браузеров вы можете открыть
консоль с помощью функциональной клавиши F12.
let х = 5;
console.log("The value of 'x' is: " + x); // явная нотация
// краткой нотации нет
print()
Функция print () открывает диалоговое окно печати для печати текущего доку-
мента.
window.print(); // явная нотация
pnnt(); // краткая нотация
prompt()
Функция р rompt () открывает модальное окно и считывает ввод пользователя.
let person = window.prompt/"What's your name9"); // явная нотация
person = prompt("What's your name9"); 11 краткая нотация
alert(person);
write()
Использование document .write () крайне не рекомендуется
(https://developer.niozilla.org/en-lJS/docs/Web/API/Document/write).
Стиль написания кода
29
Стиль написания кода
В наших примерах кода часто встречается строка "use strict"; перед любы-
ми другими инструкциями. Это указывает компилятору выполнять дополнительные
лексические проверки. В частности, он обнаруживает использование имен перемен-
ных, которые не были объявлены до присвоения им значения.
"use strict";
let happyHour = true;
hapyHour = false; // ReferenceErrur: присвоение необъявленной переменной hapyHour
Без строки "use strict' ; компилятор создал бы вторую переменную с опеча-
танным именем вместо генерации сообщения об ошибке
Лексическая структура
Сводка
• Все элементы языка чувствительны к регистру, например: const х = 0;
const X = 0; определяет две разные переменные; CONST х = 0; приводит
к синтаксической ошибке.
• Однострочные комментарии начинаются с //. Многострочные комментарии
заключаются в /* */.
• Точки с запятой для завершения операций необязательны — есть только
несколько исключений.
• Первый символ имени переменной не может быть цифрой: const 1х = 0;
приводит к синтаксической озпибке.
Чувствительность к регистру
JavaScript чувствителен к регистру. Это означает, что все ключевые слова, имена
переменных и имена функций должны быть написаны правильно. Если вы создаете
функцию Hell о(), она отличается от функции HELLO(), hello() илиИЕ11о( ).Или,
например, оператор IF (х > G) { } приводит к синтаксической ошибке, потому
что ключевое слово if определено в нижнем регистре.
Пробельные символы
Пробельные символы включают в себя пробелы, табуляции и переносы
строк111. Если есть последовательность из нескольких пробелов. JavaScript сокращает
их до одного пробела, например: ' ' -> ' \n\t‘ -> ' \ п'. Этот оставшийся
пробел отделяет элементы языка, такие как ключевые слова и имена переменных,
друг от друга. Получившийся исходный код сложнее читать для людей121, но (немно-
го) легче анализировать браузерам. Основное преимущество — меньший размер
кода, который необходимо передавать между сервером и клиентом.
Следующий скрипт является примером с минимальным количеством пробелов:
function filterEnailKeys(event){
event=event|(window.event;
const charCode=event.charCode|(event.keyCode;
const char=String, f roaiCharCode(charCode);
if(/[a-zA-Z0-9_\-\.@]/.exec(char)){return true;}
return false;
}
Следующий скрипт — тот же, но с типичным количеством пробелов;
function filterEmailKeys(event) {
event = event || window event;
const charCode = event.charCooe || event .keyCode;
const char = String.fromCharCcde(charCcde);
if (/[a-zA-Z0-9_\-\.@]/.exec(char)) {
return true;
}
return false;
}
Комментарии
31
Следующий скрипт — тот же, ио с большим количеством пробелов:
function filterEmailKeys( evt ) {
evt = evt || window.event;
const charCode = evt.charCode || evt.keyCode;
const char = String.fromCharCoce ( cnarCode );
if ( /[a-zA-Z0-9_\-\.e>]/.exec ( char ) ) {
return true;
}
return false,
}
Комментарии
Комментарии — это части исходного кода, которые по определению не будут вы-
полнены. Они позволяют оставлять заметки в коде, чтобы помочь другим людям по-
нять его. Также они позволяют закомментировать код, который вы хотите скрыть
от парсера, по не хотите удалять.
Однострочные комментарии
Двойной слеш // превращает весь последующий текст на той же строке в ком-
ментарий, коюрый не будет обработан интерпретатором JavaScript.
// Показать приветственное сообщение
alert("Hello, World'")
Многострочные комментарии
Многострочные комментарии начинаются с /* и заканчиваются */. Многостроч-
ные комментарии не могут быть вложенными.
Вот пример использования различных техник комментирования:
/* Это многострочный комментарий
который содержит несколько строк
закомментированного текста. */
let а = 1;
/* закомментировано для дальнейшего тестирования
а = а + 2;
а = а / (а - 3); // здесь что-то не так?
*/
alert('а: ' + а);
/* Этот комментарий содержит два /*, но они оба отменены */
Точки с запятой
Во многих языках программирования точки с запятой обязательны в конце
каждого оператора В JavaScript использование точек с запятой необязательно, так
как новая строка указывает на конец оператора (за исключением некоторых случа-
ев). Это называется автоматической вставкой точек с запятой (automatic semicolon
insertion):
32
Лексическая структура
// строка
х = а + Ь:
// эквивалентна:
х = а + b
Однако исключения могут быть довольно неожиданными. Автоматическая встав-
ка точек с запятой может создавать сложные для отладки проблемы:
а = b + с
(d + е) .рппт()
Приведенный выше код не интерпретируется как два оператора. Из-за скобок
во второй строке JavaScript интерпретирует код так, как если бы он был записан сле-
дующим образом:
а = b + c(d + е).print();
Хотя, возможно, вы предполагали, что он будет ингерпретирован как:
а = b + с;
(d + е).print();
Несмотря на то, что точки с запятой необязательны, предпочтительно завершать
операторы точкой с запятой, чтобы избежать недопонимания.
Литералы
Литерсы (literal) — это жестко заданное значение. Литералы предоставляют спо-
соб выражения конкретных значений в вашем скрипте. Например, справа от знака
равенства:
const myLiteral = "a fixed value";
Существует несколько типов литералов. Наиболее распространенными являют-
ся строковые литералы (string literals), но также существуют числовые литералы
(numeric literals), булевы значения (booleans), undefined, null, регулярные выражения
(regex literals), массивы (array literals) и объекты (object Literals).
Примеры объектного, пулевого и строкового литералов:
const myObject = { name:"value ', anotherName:"anctherValue' };
const isClcsed = true;
ccnst mayBel/vrong = "true";
Идентификаторы
Идентификатор (identifier) — это имя для элемента дашгых, такою как перемен-
ная. массив или функция. Существуют определенные правила:
• В идентификаторах разрешены буквы, знаки доллара, подчеркивания
и цифры.
• Первый символ не может быть цифрой.
Примеры допустимых идентификаторов:
• и
• $hello
Примечания
33
• _Hello
• hello90
1A2B3C является недопустимым идентификатором, так как начинается с цифры.
Примером идентификаторов являются имена переменных. Они подчиняются та-
ким правилам:
• Можно использовать прописные и строчные буквы, подчеркивания и знаки
доллара.
• Цифры разрешены после первого символа.
• Нелатинские символы, такие как "а", могут использоваться в именах пере-
менных, если они имеют свойства Unicode "ID_Start" или "ID_Continue”
для начала или продолжения имени соответственно.
• Специальные символы не допускаются.
• Имена переменных чувствительны к регистру: разный регистр означает
разное имя.
• Имя переменной не может быть зарезервированным словом.
Примечания
Технически вертикальная табуляция, неразрывный пробел нулевой ширины
и любой символ Unicode с категорией "Space Separator" также считаются про-
бельными символами111.
Ссылки
1. Спецификация
языка ECMAScript,
Глава 12.2 — Про-
бельные символы
(https://tc39.es/
ecma262/muliipage/
ecmascript-
language-lexical-
gra mmar. html#sec-
white-space)
2. Khan Academy
(https://www.
khanacademy,
org/computing/
computer-
programming/
programming/
writing-clean-code/
pt/readable-code)
3. ECMA-262 Спе-
цифика! щя языка
ECMAScript, Глава
12.9— Автомати-
ческая вставка то-
чек с запятой
(https://tc39.es/
ecma262/multipage/
ecmascript-
language-lexical-
grammar.
html#sec-automatic-
sem icolon-insert ion)
4. Спецификация
языка ECMAScript,
продукция
IdentifierName
(https://tc39.es/
ecma262/muhipage/
ecmascript-
language-lexical-
grammar.
htmltfprod-
IdentifierName)
Автоматическая вставка точки с запятой
(Automatic Semicolon Insertion, ASI)
В языках семейства С точка с запятой обозначает конец ин-
струкции. В отличие от других С-подобных языков, JavaScript
не требует обязательного использования точки с запятой. Вме-
сто этого точка с запятой является необязательной, и интерпре-
татор добавляет недостающие точки с запятой — в основном
в конце строки — для завершения инструкций. При этом он учи-
тывает сложные правила (https://developer.mo7illa.org/en-US/docs/
Web/JavaScript/Reference/Lexical_grammar#auromatic_semicoloii),
что может привести к конфликту' с предполагаемым поведением.
Если вы пишете код без точек с запятой в конце инструкций, вам необходимо учи-
тывать потенциально проблемные ситуации, Вот несколько общих правил, которые
помогут1 избежать проблем. Однако существует гораздо больше количество правил.
1. Выражение после одного из ключевых слов return, throw или yield
должно находиться на той же строке, что и само ключевое слово.
2. Ид ентификатор метки по еле b г е а к или continue должен находиться на той
же строке, что и ключевое слово.
3. Если строка начинается с одного из символов (, [, ', +, - или /, завершите
предыдущую строку точкой с запятой.
Хотя AS1 может упростить написание кода (нет необходимости вводить все эти
точки с запятой), на практике отсутствие точек с запятой делает программу более
сложной для отладки. По этой причине общепризнанной практикой является ис-
пользование точек с запятой в конце инструкций. Тем не менее существование ASI
может создавать некоторые ошибки, которые сложно устранить, если вы не знаете,
на что обращать внимание.
Примеры
Напечатанный код Интерпретирован как Что задумывалось
return 2а + 1 return, 2a + 1 ; return 2*a + 1;
function getObject() { return { // some lines } } function getObject() { return; { // some lines }; } function getObject() { return { // some lines }; }
i ++ i; ++; i++;
См также
35
В первом случае программист предполагал, что будет возвращено значение
2*а + 1 вместо этого код вернул undefined. Аналогично во втором случае про-
граммист предполагал, что будет возвращено содержимое, заключенное в фигурные
скобки {}, но код вернул undefined. Из-за этой особенности в JavaScript считает-
ся лучшей практикой никогда не разрывать строки внутри инструкции и никогда
не размещать открывающую скобку на отдельной строке.
См. также
Ссылка на MDN
(htvps://deve]oper.
mozilla.nrg/en-US/'
docs/Web/JavaScript/
Reference/Lexical_
grammar#automatic_
sem icolon J nsert ion)
Ссылка на ECMA
(https://262.ecma-
international.org/13.0/#sec-
a utom at ic- semicolo n-
insertion)
Пробельные симво-
лы и точки с запятой
в JavaScript
(https://en.wikipedia.
org/wiki,JavaScript-
syntax#Whitespace_and_
semicolons)
Зарезервированные слова
В JavaScript некоторые токены (слова) имеют специальное значение (семантику). По
этому их нельзя использовать в качестве имен переменных, функций, классов и т. д,И| 121.
Некоторые из inn являются зарезервированными словами в общем смысле; другие за-
резервированы только в определенном контексте; третьи зарезервированы для возмож-
ного использования в будущем, не имея на данный момент специальной функциональ-
ности; четвертые были определены в устаревших версиях ECMAScript 1997-99 годов.
Список таких специальных слов по состоянию на 2022 год приведен ниже.
abstract delete goto package transient
await do if private true
boolean double implements protected try
break else import public typeof
byte enum in return var
case export instanceof short void
catch extends int static volatile
char false interface super while
class final let switch with
const finally long synchronized yield
continue float native this
debugger for new throw
default function null throws
Кроме того, существуют предопределенные методы, такие как forEach(), пре-
допределенные модули, такие как Math, или предопределенные объекты, такие
как Biqlnt. имен которых также следует избегать.
Ссылки
1. ЕСМА. Ключевые
слова
(https://262.ecma-
international. org/#sec-
keywords-and-reserved-
words)
2. MDN: Ключевые слова
(https://developer.
mozilla.org/en-US/
docs/Web/JavaScript/
Refer ence/Lexical.
gra m mar#keywords)
Переменные
Цель
Компьютерные языки нуждаются в использовании переменных. Зачем это нуж-
но? В большинстве случаев программы решают не единичные задачи, такие как кон-
кретный вопрос: «Какова длина окружности с радиусом 5 см?» Такой конкретный во-
прос можно решить без использования переменных:
alert(2 * 5 * 3.14);
Однако большинство вопросов носят более общий характер: «Какова длина окруж-
ности с произвольным радиусом?» Вам не нужно писать отдельную программу для ра-
диуса 5 см, другую для радиуса 6 см. третью для радиуса 7 см и так далее. Вам нужно
написать одну программу, которая вычисляет длину окружности для всех возможных
радтгусов. Программа требует ввода (от пользователя, другой программы, базы дан-
ных и т. д.), который указывает, для какого значения она должна выполняться:
let г = proirpt("How Dig is the radius of your circle?');
alert(2 * r * 3.14);
...или даже лучше:
let г = prompt("How big is the radius of your circle9’);
alert(2 * r * Math.PI);
Эти два примера решены в общем виде. Они запрашивают у пользователя желае-
мый радиус, сохраняют введенное значение в переменной с именем г и вычисляют
длину окружности, используя эту переменную. Переменная г вводится с помощью
ключевого слова let. Также существует вторая переменная. Модуль Math предопре-
деляет переменную PI с ключевым словом const:
const PI = 3 1415926535Е9793;
В JavaScript переменные могут использоваться аналогично переменным в мате-
матических формулах. Во время выполнения программы значения переменных хра-
нятся в оперативной памяти компьютера (RAM), откуда пни могут быть извлечены
позже во время выполнения программы. Можно представить переменную как не-
большую коробку, в которую вы помещаете значение и извлекаете его, когда это не-
обходимо.
Переменные являются краеугольным камнем в переходе от решения отдельных
задач к стратегии и, соответственно, к алгоритму.
Объявление и инициализация
Если вы хотите использовать переменную, мы рекоменду-
ем явно объявлять ее (https://developer.rnozilla.org/en-US/docs/’Web/
]avaScript/Guide/Grammar_and_Typesffdeclarations).
38
Переменные
Это не является обязательным, но дает значительные преимущества
Во многих случаях объявление переменной сопровождается инициализацией,
например:
let х = 0;
Здесь объявление — это let х;, а инициализация — х = 0;. Однако можно опу-
стить часть инициализации:
let х;
В этом случае значение переменной будет undefined
Ключевое слово let
Ключевое слово let вводит переменную, значение которой может изменяться не-
сколько раз:
let х = 0;
// ...
х = х + 5;
// ...
х = -4;
// ...
Ключевое слово const
Ключевое слово const вводит переменную, которая должна быть инициализиро-
вана сразу. Более того, это первое значение никогда не может быть изменено. Это по-
могает движку JavaScript оптимизировать код для повышения производительности.
Используйте const как можно чаще:
const maxCapacity = 100;
// .. .
maxCapacity = maxCapacity + 10; // невозможно
let maxCapacity =110; // невозможно
Когда вы работаете с объектами, например с массивами, в сочетании с ключевым
словом const, правило остается тем же: вы не можете присвоить другое значение
(объект, массив, число и т. д.) переменной. Тем не менее ее элементы могут быть из-
менены:
const агг = [1, 2, 3];
агг = [1, 2, 3, 4];
arr = new Дггау(10);
агг[0] = 5;
alert(arr);
агг ,push(42);
alert(arr);
// невозможно
// невозможно
// ок: 5, 2, 3
И ок: 5, 2, 3, 42
В некоторых случаях переменные const записываются в верхнем регистре, на-
пример PI Это соглашение, но оно не является обязательным.
Ключевое слово var
На первый взгляд va г идентично let. Однако область видимости переменных, объ-
явленных при помощи let, отличается от переменных, объявленных с помощью var.
Типы данных
39
Пропуск объявления
Вы можете присвоить значение переменной без ее предварительного объявле-
ния. Раньше JavaScript позволял присваивать значения необъявленным перемен-
ным, что создавало необъявленную глобальную переменную. Это является ошибкой
в строгом режиме и должно быть полностью избегаемо111. Другими словами, перемен-
ная попадает в глобальную область видимости.
Пока у вас нет веских причин, следует избегать использования глобальной обла-
сти видимости, так как ее применение может привести к нежелательным побочным
эффектам:
// прямое использование radius без какого-либо ключевого слова для его объявления
/* 1 */ radius = 5;
/* 2 */ aiert(2 * radius * 3.14);
Иногда такие ситуации возникают случайно. Если в исходном коде допущена опе-
чатка, JavaScript использует две разные переменные — оригинальную и новую с не-
правильно написанным именем, даже если вы используете одно из ключевых слов
let, const или var.
let radius = 5; // или без 'let'
alert("Test 1");
// ... позже в коде
radus = 1; // опечатка не будет обнаружена
alert("Test 2');
Вы можете указать JavaScript искать такие опечатки, добавив команду "use
strict"; в первую строку ваших скриптов:
"use strict";
let radius = 5;
alert(“Test Г);
// ... позже в коде
radus =1; // опечатка будет обнаружена, и будет выдано сообщение об ошибке
alert('Test 2"); // никогда не выполнится
Типы данных
Программисты, знакомые со строго типизированными языками, такими как Java,
могут заметить, что в предыдущей главе отсутствует возможность определения типа
переменных. JavaScript поддерживает множество различных типов данных. Однако
их обработка и поведение значительно отличаются от таковых в Java. В следующей
главе вы узнаете об этом.
Область видимости (Scope)
Область видимости — это диапазон последовательных инструкций JavaScript
с четко определенными началом и концом. JavaScript «знает» четыре типа обла-
стей видимости: блочная (block), функциональная (function), модульная (module)
и глобальная (global) области видимости. В зависимости от вида объявления и его
местоположения переменные находятся в таких областях видимости. Они «видны»
или «доступны» только в пределах своей области видимости. Если вы попытаетесь
получить к ним доступ извне, произойдет ошибка.
40
Переменные
Блочная область видимости (Block Scope)
Пара фигурных скобок {} создает блок. Переменные, объявленные внутри блока
с помощью let или const, привязаны к этому блоку и не могут быть доступны за его
пределами:
"use strict ;
let а = 0;
// ...
if (а - в) {
let х = 5;
alert(x);
} else {
alert(x);
}
alert(x);
// показывает число 5
// ReferenceError (при другом значении 'а')
// ReferenceError
Переменная х обт.явлена внутри блока (в этом простом примере блок состоит все-
го из двух строк). Она недоступна за пределами блока, который заканчивается закры-
вающей фигурной скобкой } в строке else. То же самое относится к случаю, когда пе-
ременная х объявлена с помощью const вместо let.
Будьте осторожны с ключевым словом var; его семанти-
ка отличается! Во-первых, var не ограничивается блочной об-
ластью видимости. Во-вторых, оно приводит к технике, называе-
мой поднятием (hoisting) (https://developer.mozilla.org/en-US/docs/
Glossary/Hoisiing), которая используется в JavaScript с первых дней
его существования.
Поднятие изменяет семантику различных объявлений «под капотом». В слу-
чае с var оно разделяет объявление и инициализацию на два отдельных выраже-
ния и перемещает часть объявления в начало текущей области видимости. Таким
образом, переменная объявляется, но не инициализируется, если вы используете ее
до строки, где она объявлена в исходном коде.
Скрипт:
"use strict";
alert(x); // undefined, не ReferenceError!
x = 1; // корректно, несмотря на "use strict"
alert(x); // показывает 1
var x = 0:
преобразуется в:
"use strict";
var x;
alert(x); // undefined, не ReferenceError!
x = 1;
alert(x); // показывает 1
x = 0;
С другой стороны, ключевое слово let оставляет объявление в строке, где оно на-
писано:
Область видимости (Scope)
41
"use strict";
alert(x); // ReferenceError
x = 1; // ReferenceError
alert(x); // ReferenceError
let x = 0;
Есть и другие различия. Вот версия первого примера из этой главы, где let заме-
нено на var
"use strict";
let a = 0;
// ..
if (a == 0) {
var x = 5; // ’var' вместо let
alert(x); // показывает число 5
} else {
alert(x); // ReferenceError (при другом значении a')
}
alert(x); // показывает число 5 !!
Мы рекомендуем полностью избегать использования vaг по двум причинам:
1. Техника поднятия в JavaScript нелегка для понимания.
2. Другие языки семейства С не используют ее.
Вместо var используйте ключевое слово let.
Функциональная область видимости (Function Scope)
Функция создает свою собственную область видимости Переменные, объявлен-
ные в области видимости функции, не могут быть доступны извне:
"use strict";
function func_1() {
let x = 5; // x может использоваться только в func_1
alert("Irside function: " + x);
}
func_1();
aiert(x); // Вызывает ошибку
Функциональная область видимости иногда называется локальной областью ви-
димости (local scope), поскольку именно так она называлась в более старых версиях
ECMAScript.
Модульная область видимости (Module Scope)
Можно разделить большие скрипты на несколько файлов и позволить функци-
ям и переменным взаимодействовать друг с другом. Каждый файл создает свою соб-
ственную область видимости — модульную. Глава JavaScript/Modules рассказывает
об этом подробнее.
Глобальная область видимости (Global Scope)
Переменные или функции находятся в глобальной области видимости, если
они объявлены на верхнем уровне скрипта (вне всех блоков и функций):
"use strict*;
let х - 42; // 'х' принадлежит глобальной области видимости
42
Переменные
// определяем функцию
function func_1() {
// используем переменную из глобального контекста
alertf'In function: " + х);
}
// запускаем функцию
func_1(); // показывает "In function. 42
alert(x); // показывает "42’
х объявлен на верхнем уровне, следовательно, он находится в глобальной обла-
сти видимости и может использоваться везде, Но в следующем примере объявление
х заключено в { }. Следовательно, оно больше не находится в глобальной области
видимости:
"use strict";
{
let х = 42; П 'x' не в глобальной области зидимости
}
alert(x); // ReferenceError
Подсказка: использование глобальной области видимости не считается хоро-
шей практикой. Это может привести к нежелательным побочным эффектам, Вместо
этого попробуйте модулизировать ваш код и позволить частям взаимодействовать
через интерфейсы.
Ссылки
MDN: Объявления переменных (https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Guide,/Grammar_and_Types#declarations)
Типы данных
Введение
Каждая переменная в JavaScript имеет определенный тип данных (Number,
String, Boolean,...) — до тех пор, пока в ней хранится значение. Тип значения опре-
деляет тип переменной. В отличие от строго типизированных языков, в JavaScript
можно со временем присваивать переменной значения разных типов, что может из-
менить тип переменной. Это называется слабой или свободной типизацией (weakly
or loosely typing). Преимущество такого подхода заключается в том, что программи-
сты на JavaScript имеют широкие возможности и свободу действий для использова-
ния переменных (или злоупотребления ими). С другой стироны, в строю типизиро-
ванных языках множество формальных ошибок может быть обнаружено на этапе
компиляции.
JavaScript поддерживает семь примитивных типов данных (Number, String,
Boolean, Biglnt, Symbol, Undef ined, Null) и различные другие типы данных, кото-
рые все являютсяпроизводными от Object (Array, Date, Error, Function, RegExp)'11121.
Объекты содержат не толью* значение, но и методы, и свойства. То же самое может про
исходить с примитивными типами данных. Если они пытаются вызвать методы, дви-
жок JavaScript «оборачивает» (wraps) их соответствующим объектом-оберткой и вызыва-
ет его методы вместо этого. Этот подход иногда называют упаковкой (boxing).
Вы можете задаться вопросом, почему мы описываем типы данных и инициали-
зацию в одной главе. Причина в том, что они тесно связаны друг с другом. Инициа-
лизация (и последующие присваивания) значения переменной определяет ее тип,
как было отмечено выше. Именно поэтому при инициализации не указывается тип,
в отличие от некоторых других языков:
private int 1=0; /* Java */
(Примечание: JSON — это текстовый формат данных, а не тип данных. Как тако-
вой он не зависит от языка. Он использует синтаксис объектов JavaScript.)
Категории типов данных
Типы данных объясняются в следующих главах.
Примитивные типы данных:
• Объекты
• Массивы
• Даты
• Регулярные выражения
Ссылки
1 MDN: Типы данных
(https://developer.
mozilla org/en-US/
docs/W eb/J avaScript/
Language_Overview)
2. MDN: Подробнее
о типах данных
(hnps://developer.
mozilla.org/en US/docs/
W eb/J avaScript/Dat a_
structures)
Примитивные типы данных
Примитивные гипы используют фиксированный формат; не-
которые могут содержать только ограниченное количестве- опре-
деленных значении. В отличие от inix объекты более сложные,
особенно включаюшие методы и свойства.
За исключением null и undefined примитивные типы име-
ют соответствующий объект-обертку (https://developer.mozilla.org/
en-US/docs/Web'JavaScript/Data_struciures#primitive_values) с мето-
дами, специфичными для данного типа данных.
Поэтому здесь вы найдете описания некоторых методов.
Строка (String)
Строка — это тип даштых для хранения текста произвольной длины. Перемен-
ные типа «строка» создаются путем присваивания им строкового литерала. Строко-
вые литералы могут быть заключены в двойные ( ") или одинарные (' ) кавычки:
"use strict";
const myName.,1 = Mike"; // двойные кавычки
const myName_2 = Monica ; // апостооф
const myName_3 = ' iiaJuiQito' ; // нелатинские символы
Если ваш строковый литерал содержит " или ', вы можете использовать другой
символ в качестве внешнего разделителя или экранировать их с помощью \:
use strict";
const book_1 = "Mike s book';
const monica.1 = Here name is "Monica'.';
const book_2 = MikeVs book';
const monica_2 = Here name is \'MonicaV'.";
Если ваш строковый литерал формируется из фиксированного текста и динами-
ческих частей, вы можете использовать технику шаблонных литералов. В этом слу-
чае литерал заключается в обратные кавычки ’ ’ и содержит переменные и выра-
жения
"use strict ;
const а = 1;
const b = 2;
const resultMessage = The sum of ${a} and ${b) is. ${a + b}. ;
// то же самое
The sum of 1 + a + ' and ’ + b + ' is: ' + (a + b);
alert(resultMessage);
Оператор + объединяет две строки, например ale rt (" Hello" +
"world1");. Кроме тою, существует множество методов (https://
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/String^instancejnethods) для работы со строками.
Примечание: в JavaScript нет отдельного типа данных для сим-
волов (character) или байтов (byte).
Свойства и методы для строк
45
Свойства и методы для строк
Мы покажем некоторые часто используемые методы.
length
length — это свойство, а не метод. Поэтому оно не требует скобок (). Оно возвра-
щает длину строки в виде целою числа:
const foo = "Hello!";
alert(fоо length); Il 6
concat(text)
Метод возвращает строку, в которой text добавлен к исходной строке:
const foo = "Hello";
const bar foo.concat(" World! ’);
alert(bar); // HelLc World!
indexOf (searchText)
Метод возвращает позицию первого вхождения searchText, начиная с 0. Если
sea rchText не найден, возвращается -1. Метод чувствителен к регистру:
const foo = "Hell- , World! How di. you de9";
alert(foo.indexOf(" ")); //6
const hello = "Hello world, welcome to the universe.";
alert(hello.indexOf("welcome")); // 13
lastlndexOf(searchText)
Метод возвращает позицию последнего вхождения searchText. Если searchText
не найден, возвращается -1. Метод чувствителен к регистру:
const foo = 'Hello, World1 How do you do9";
alert(foo,last!ndexOf( ’)); // 24
replace(text, newtext)
Метод возвращает строку, в которой text заменен на newText в исходной строке.
Заменяется только первое вхождение. Метод чувствителен к регистру:
const foo = "fuo bar foo bar foo";
const newString = toe.replace("bar , "NEW"):
alert(foo); // foo bar foo bar foo
alert(newStnng); // foo NEW foo bar foo
Как видно, метод replace только возвращает новое содержимое и не изменяет
исходную строку в foe
slice(start f, end])
Метод возвращает подстроку, начиная с позиции sta rt:
"hello".slice(1);
// ' ello
46
Примитивные типы данных
Если указан end, извлечение происходит до, но не включая позицию end:
"hello".sllce(1, 3); // "el"
Метод slice позволяет извлекать текст, ссылаясь на конец строки, используя от-
рицательные индексы:
"hello".slice(-4, -2); // "еГ
В отличие от substring, метод slice никогда не меняет местами позиции start
и end Если start находится после end, slice попытается извлечь содержимое,
как указано, но, скорее всего, выдаст неожиданный результат'
"hello".slice(3, 1); // ““
substrfstart [, number of characters])
Метод устарел (https://developer.mozilla.org/en-US/docs/Web/
JavaScript/Reference/Global_Objects/String/substr). Вместо него ис-
пользуйте substring или slice.
substring(start [, end])
Метод извлекает подстроку, начиная с позиции start:
hello".substring(l); // ' ello
Если указан end, извлечение происходит до, но не включая позицию end:
"hello".substrings, 3); // el"
Метод substring всегда работает слева направо. Если позиция start больше по-
зиции end. substring поменяет их местами; хотя иногда это полезно, это не всегда
то, что нужно; другое поведение предоставляет метод slice:
"hello substring^, 1);
И "el"
toLowerCase()
Метод возвращает текущую строку7 в нижнем регистре:
const foe = "Hello!";
alert(foo,toLowerCase()); // helio1
toUpperCaseQ
Метод возвращает текущую строку в верхнем регистре:
const foo = "Hello!";
alert(foo todpperCase()); // HELLO1
Число (Number)
Numbe r — это пдин из двух числовых типов (второй — Biglnt). Number хранит це-
лочисленные значения, а также значения с плавающей точкой в унифицированном
64-битном формате, определенном стандартом IEEE 754. Это означает, что в JavaScript
Свойства и методы для чисел
47
нет отдельных типов данных для целых чисел и чисел с плавающей точкой, как в не-
которых других языках. Возможный диапазон значений приблизительно составляет
от -1030" до +10зп" с различной точностью в зависимости от удаленности от 0.
В диапазоне от -(253 - 1) до +253 - 1 нет неопределенности для цел счисленных опера-
ций. 253 - 9,007,199,254,740,992, что немного меньше, чем 101К:
"use strict*;
let counter =20. // без десятичной точки
a]ert(counier + " " + typeot counter);
let degree = 12.1; // с десятичной точкой
alert(degree + " " + typeo* degree);
Для Number доступны обычные арифметические операторы (степень — **, мо-
дуль — %), операторы сравнения (<,>,...) и побитовые операторы. В отличие от не-
которых других языков, деление двух целых чисел может привести к результату с де-
сятичными знаками, например alert (1 /3);.
Свойства и методы для чисел
Работа с числами поддерживается множеством свойств и методов. Внугренне
они реализованы в разных областях:
• Встроенный объект Math предоставляет свойства, представляющие общие
математические константы, такие как п или е. Синтаксис: Math.xyz (без
скобок).
• Встроешпяй объект Math предоставляет общие математические функции,
такие как sin или log. Синтаксис: Math. xyz() (со скобками).
• Объект Number предоставляет свойства, характеризующие реализацию типа
данных number, такие как МАХ_VALUE или NEGATIVE.INFINITY. Синтаксис:
Number. xyz (без скобок).
• Объект Number предоставляет статические методы, которые проверяют
связь между числами и другими типами данных, например islnteger
или parseFloat. Синтаксис: Number. xyz() (со скобками).
• Объект Number предоставляет методы экземпляра, которые действуют
на кинкретные числовые значения или переменные, например
toExpunential или toFixed. Синтаксис: value.xyz() (со скобками).
// несколько примеров
"use strict";
const var_1 = Math.PI;
alert(var_1);
a)ert(var_l,toFixed(2));
const var_2 = Math.sqrt(3);
alert(var_2);
alert(Number.MAX. VALUE);
alert(Number.isInteger(123));
alert(Number.islnteger(12.3));
// true
// false
Мы показываем некоторые свойства и методы, которые часто
используются. Для полного списка обратитесь к:
• Math (https://developer.n^ziUa.org/en-US;docs/Web/JavaScript/
Reference/Global.ObjectS/'Math)
48
Примитивные типы данных
N umbers (hnps://developer.mo2 dla.org/en-l JS/docs/Web/Java Script/ И.ЖЯЙЕ
Reference/Global .Objects/Number)
Свойства
Наиболее часто используемые константы:
• Math.E—возвращает константу е.
• Ma th. PI — возвращает константу п.
• Math. L N10 — возвращает натуральный логарифм 10.
• Math. LN2 — возвращает натуральный логарифм 2.
• Math. SQRT2 —возвращает квадратный корень из 2.
Math.ceil(number)
Возвращает наименьшее целое число, большее или равное переданному числу:
const mylnt = Math.ceil(90 8);
alert(mylnt); // 91
alert(Math.ceil(-90.8)); // -90
Math.floor(number)
Возвращает наибольшее целое число, меньшее или равное переданному числу:
const mylnt = Math floor(90 8);
alert(mylnt); // 90
alert(Math.floor(-98 8)); // -91
Math.round(number)
Возвращает ближайшее целое число к переданному числу (округляет):
alert(Math.round(90 8)); // 91
alert(Math.round(-90.8)); 11 -91
alert(Math.rodrd(90.3)); // 9И
alert(Mach.round(-90 3)); // -90
Math.max(number_1, number_2)
Возвращает большее из двух переданных чисел:
alert(Math.шах(8 3, 9)); // 9
alert(Math.max(8 3, -9)); // 8.3
Math.min(number_1, number_2)
Возвращает меньшее из двух переданных чисел:
alertfMath.min(8 3, 9)); // 8.3
alert(Math.min(8.3, -9)); 11 -9
Math.random()
Генерирует псевдослучайное число между 0 и 1:
alert(Math.ranoom());
biglnt
49
Number.parsetnt(string) и Number.parseFloat(string)
Эти два метода преобразуют строки в числа. Они сканируют строку слева напра-
во. Когда они распознают символ, отличный от 0-9, они завершают сканирование
и возвращают преобразованные числа, прочитанные до этого момента (pa гseFloa t
принимает десятичную точку). Если первый символ отличен от 0-9, они возвращают
Math. NaN , что означает «Не число».
Подсказка: в коде не обязательно указывать 1 Number'.
const х = parselnt(’'7.5 );
alert(x); // 7
const у = parse!nt("Five ');
alert(y); Il NaN
const z = parseFloat('2.8") + 3;
alert(z); //5.8
// научная нотация принимается
alert(parseFloat("123 456e6 )); // 123456000
Biglnt
Biglnt — эго тип данных, который представляет целые числа произвольной
длины. Таким образом, это формат переменной длины (концептуально), ограничен-
ный только доступной оперативной памятью.
Biglnt создается либо путем добавления ' п' в конец целочисленного литерала,
либо с помощью функции Biglnt ():
"use strict";
let hugeNumber_1 = 12345678901234567890П; // n' в конце
alert(typeof hjgeNumDer_1);
let hugeNumber_2 = ’iiglnt("1234567840?234567890'), // без 'n'
alert(typeof hjgeNuniDer_2);
11 'маленький' Biglnt м<жно создать из целочисленного значения
let hugeNurnber_3 = 3iglnt(123);
alert(typeof hjgeNumber.3);
Biglnt поддерживает арифметические операторы + - * / **, операторы срав-
нения и большинство побитовых операторов.
Boolean
Логические переменные (Boolean) могут содержать одно из двух возможных зна-
чений: true или false. JavaScript представляет false как логическое значение
false, число 0. NaN, пустую строку или встроенные типы undefined либо null. Лю-
бые другие значения рассматриваются как t rue:
"use strict";
let firstLoop = true;
alert(typeof firstlcop);
Undefined
Переменные, которые были объявлены, но не инициализированы каким-либо
значением, имеют тип данных undefined:
50
Примитивные типы данных
"use strict ;
let х;
// ...
alert(typeof х);
if (х -- undefined) {
// исправляем отсутствие инициализации
х = 0;
}
alert(typeof х);
// ...
Null
В JavaScript null считается одним из примитивных значений, поскольку его пове-
дение кажется примитивным. Однако при использовании оператора typeof он воз-
вращает 1 oDject". Это считается ошибкой, но она не может быть исправлена, так
как это нарушит работу большего объема скриптов'11.
Symbol
Symbol представляет собой уникальный идентификатор. Символы могут иметь
описание, которое передается в виде строки в их конструктор.
"use strict";
// 'person' - это символ с описанием "Olaf
const person = Symbol (''Olaf' );
alert(perscn description); // Olaf
Символы (https://developermozilla.org/en-US/docs/Web/JavaScript/
Reference/Global°/o200bjects/Symbol) используются как ключи в объ-
ектах (внутри [ ]) для гарантии уникальности.
См. также
Определения ECMAScript о типах данных (hltps://262.ecina-
b1ternati0nal.0rg/#sec-ecmascript-data-types-and-values)
Ссылки
MDN: Null (https://developer.mozilla.org/en-US/docs/Glossary/NullJ
Объекты
В JavaScript объект (Object) (hnps://developer.mozilla.org/en-
US/docs/Web/JavaScript/Data_stnictures#objects) — это коллекция
свойств; свойства представляют собой пары «ключ-значение».
Ключи могут быть строками (Strings) или символами (Symbols).
Значения могут бьпь любого типа данных, включая функции
(в этом случае они называются методами).
Объекты выглядят как ассоциативные массивы, реализованные в виде хеш-
таблиц. Однако на практике движки JavaScript могут реализовывать их другими спо-
собами для достижения оптимальной производительности.
Учтите, что объекты JavaScript не идентичны JSON. JSON — это формат текстового
представления ('сериализации' / 'десериализации') объектов, который также может
быть использован в других языках или в текстовом редакторе.
Создание объекта
Синтаксис JavaScript поддерживает различные способы создания объектов.
«Литеральная нотация» с использованием фигурных скобок {}
"use strict";
// пустой объект (без свойств)
const obj_0 = {};
alert(JSON.stringify(obj _0));
// 'obj_1' содержит набор из трех свойств Значение ключа 'с' -
// второй объект с пустым набором свойств.
const opj_1 = { a: "Any string", b: 42, с: {} };
alert(JSGN.stringity(obj_1)),
// использование переменных
const а = "Any string";
const b = 42;
const c = {};
const obj_2 = { a: a, b: b. c: c };
alert(JSON.stnngify(obj_2));
// сокращенное использогание переменных
const obj_3 = { a, b, c },
alert(JSON.stringify(obj_3));
52
Объекты
Конструктор
Конструктор new Object () создает новый объект:
use strict";
const obj_4 = new Object({ a 5, b 42 });
alert(JSON. stnngify(obj_4));
Object.create()
Метод Object. create () создает новый объект из существующего объекта:
"use strict";
const obj_5 = Object create({ a: 5, b: 42 });
alert(JSON.stringify(obj_5)); // ???
alert(JSON.stringify(opj_5 a));
console.log (obj_5);
Чтение свойства
Каждое свойство состоит из нары «ключ-значение». Чтобы прочитать значение
свойства, можно использовать его ключ одним из двух синтаксических способов: то-
чечная нотация или скобочная нотация:
use strict ;
const person = {firstName: 'Albert", lastName: 'Einstein" };
// точечная нотация
alert(person.firstName); // без " " или '
// скобочная нотация
alert(person["firstName ]); II обязательно использовать строку
// скобочная нотация с использованием переменной
const fn = "firstName";
alert(person[fn]);
Что делать, если ключи неизвестны? Чтобы получить список всех существующих
ключей, используйте метод Object. keys(). Он возвращает массив, элементы кото-
рого являются строками. Эти строки можно использовать в цикле для доступа к зна-
чениям. Поскольку такие циклы нужны во многих случаях, JavaScript предлагает
специальный языковой элемент для этой ситуации. Цикл for .. in выбирает клю-
чи и проходит по всем свойствам:
"use strict";
const person = {firstName: "Albert", lastName: 'Einstein" };
alert(Object.keys(person)); // firstName, lastName
// Цикл for . in выбирает ясе существующие ключи и проходит пс свойствам
for (const k in person) {
alert('The key is: ' + k + ’. The value is: ' + person[k]);
}
Аналогично методу Object.keys() существуют два метода Object. values()
и Ob j ect. entries () для получения значений соответственно свойств (ключ и зна-
чение). В последнем с.гучае вы получаете массив массивов (с двумя элементами каж-
дый):
Добавление или изменение свойства
53
"use strict";
const person = {firstName: "Albert", lastName: "Einstein” };
alert(Object.values(person)); // Albert, Einstein
// Циклы for .. of отличаются от for .. in по синтаксису и семантике; см. главу 'Циклы
for (const, [k, v] of Object.entries(person)) {
alert('The key is: ' + k + '. The value is. + v);
}
Добавление или изменение свойства
Вы можете использовать точечную нотацию (dot notation) или скобочную нота-
цию (bracket notation) для добавления или изменения свойств. Синтаксис для опера-
ций чтения и записи не отличается:
"use strict";
const person = {firstName. Albert", lastName: "Einstein" };
// добавление свойств
person.Dornin = "Ulm";
person!."profession ] = "Physicist";
alert(JSON.stringify(person));
// изменение свойсте
person.bornln = "Germany";
person!"profession"] = "Theoretical Physics';
alert(JSON.stringify(person));
В приведенном выше примере переменная person создана с использовани-
ем ключевого слова const. Это означает, что нельзя присвоить ей новое значение,
но можно изменять ее свойства. При изменении свойств исходный объект остается
неизменным.
Удаление свойства
Оператор delete удаляет все свойство из объекта — как ключ, так и значение.
Это отличается от случая, когда в значение записывается null или undefined.
Опять же можно использовать как точечную, так и скобочную нотацию:
"use strict’;
const person = {firstName "Albert', lastName1 'Einstein", bornln: "Ulm", profession:
"Physicist" };
delete person.bornln;
delete person! profession'];
alert( JSON.strinqify(perso-)));
Объединение объектов
JavaScript предлагает синтаксис spread syntax (три точки). Он раскрывает объ-
ект до его свойств (пар «ключ-значение») или массив до его элементов. Это может
быть полезно, когда нужно объединить несколько объектов в один:
"use strict";
const person = {firstName: Albert", lastName: Einstein' };
54
Объекты
const address = {city: "Ulm' };
// раскрываем два объекта (и объединяем их)
const newPerson = {...person, ...address};
alert(JSON stringify(newPerson));
// Результат - объект с тремя свойствами. Все значения - строки.
// {firstName: "Albert1, lastName: "Einstein", city: "Ulm'}
// Это отличается от версии без синтаксиса "spread":
const newPersonl = {person, address};
alert(JSON.stringify(newPerson1));
// Результат - объект с двумя свойствами. Оба значения - объекты.
// {person: {firstName: "Albert", lastName- "Einstein"}, address’ {city: 'Ulm }}
Функции/методы как часть объекта
Значение свойства может содержать тело функции: смотрите
здесь (https:/7developer.mozi]la.org;en-US/docs/Web/favaScript/Guide/
Working_with_Objects#defining. methods).
В этом случае функция называется методом:
use strict";
11 только определения, без выполнения!
const city = {
showName: function, (cityName) {
if (typeof cityName === "undefined") {
alert("Sorry, I don t know my name.");
} else {
alert("The name of the city is: " + cityName);
}
},
// это тоже работает'
showPopulation(count) {
alert(count + " Inhabitants");
}.
};
console.loq(city);
// выполнение
// JSON.stringify() не поддерживает сериализацию методов. Используйте console.log().
city.showName();
city.showName( Nairobi");
city .showPopulati.Tn(45U0000);
Массивы
В JavaScript массив (array) — это объект, в котором можно хранить набор значе-
ний под одним именем переменной. Пока что все так же, как и во многих других язы-
ках. Однако есть и итличия.
• Не обязательно, чтобы значения были одного типа
данных. Вы можете поместить в массив все что угодно
и не беспокоиться о типах данных (хотя существуют
и типизированные массивы (hnps://developer moziUa.org/
en-US/docs/Web/JavaScripi/Typed_arrays), где все значения
имеют одинаковый тип данных).
• При создании массива не обязательно указывать его размер, но вы можете это
сделать. Массивы автоматически увеличиваются в размере. Это делает их очень
удобными в использовании, но не подходящими для задач численного анализа.
• Поскольку массивы являются объектами, они имеют методы и свойства,
которые можно вызывать по мере необходимости. Например, свойство . length
указывает, сколько элементов в данный момент находится в массиве. Если вы
добавляете больше элементов в массив, значение . length увеличивается.
• Отсчет элементов начинается с 0, и это означает, например, что пятый элемент
находится по индексу [ 4 ].
(Подсказка: при работе с массивами всегда используйте квадратные скобки с не-
отрицательными целыми числами, например аг г [ 3 J = 42 ;. Технически можно
использовать и точечную нотацию, но это приводит (по крайней мере для начинаю-
щих) к неожиданному поведению.)
Создание массива
Во-первых, как и для всех объектов, существует конструктор-
"use strict";
const arr_1 = new Array(); // пустой массив
alert(arr_1.length);
const arr_2 = new ArrayfS, 2, 4); // три элемента
alert(arr_2);
Синтаксис JavaScript поддерживает квадратные скобки при создании или работе
с массивами:
"use strict";
const агг_1 = []; 11 пустой массиь
alert(aT_1 .length);
const arr_2 = [0. 2, 4]; // той элемента
alert(arr_2);
Вы можете заранее задать размер массива при его объявлении:
"use strict";
const a-r_3 = new Array(50); // 50 элементов
alert(arr_3.length);
56
Массивы
Доступ к элементам массива
Элементы массива доступны для чтения или записи с использованием стандарт-
ной нотации с квадратными скобками:
use strict' ;
const arr.4 = [0, 2, 4, 6, 8];
alert(arr_4[3]); // 6
arr_4[0] = 9;
alert(arr_4); // 9, 2, 4, 6. 8
Если вы обращаетесь к элементу за пределами текущей длины массива, размер
массива увеличится, и новый элемент будет создан:
"use strict ;
const arr_5 = [0, 2, 4, 6, 8];
arr_5[10] = 9;
alert(arr_5); // 0,2,4,6.8,,,,,,9
alert(arr_5.length); // 11
Различные типы данных
В массиве можно хранить значения разных типов данных:
use strict";
const arr_6 = [0, "two", 4]; // числи и строка
console.log(arr_6); // [0, "two", 4]
// и даже значения пипа массив могут быть сохранены
const агг_7 = [10. 11];
агг_7[2] = агг_6; // массив в массиве
console.log(arr_7); // [10, 11, [0, "two , 4]]
console.log(arr_7.length); 11 3
Вложенные массивы
Как было показано ранее, элемент массива может быть массивом (который сам
может содержать элементы типа «массив^ (который сам может содержать...)). Это мо-
жет происходить как во время выполнения, так и при инициализации. Чтобы полу-
чить доступ к элементам на более глубоких уровнях, необходимо указать столько пар
квадратных скобок [ ], сколько требуется для достижения этого уровня:
"use strict";
const агг_8 = [ [0, 1], [10. 11, 12, 13], [20, 21] ];
console.log(arr._8[2]); // один уровень ведет к массиву чисел: [20, 21]
console.logfarr..8[1][1]); // два уровня ведут к числу: 11
// тс же самое с присваиваниями ...
arr_8[2][0j = "twenty";
console.log(arr..8[2]); // ["twenty", 21]
...и немного сложнее:
"use strict";
const arr_9 = []; // пустой массив
arr_9[0] = [];
arr_9[O]l0] = [];
arr_9[0]!0][2] = "Hallo world!';
console.log(arr_9); // [[[undefined, undefined, 'Hallo world1"]]]
arr_9[2] = 'Third element of first level";
console.log(arr_9);
// [[[undefined, undefined, Hallo world!"]], undefined, "Third element of first
level']
Свойства и методы
57
Свойства и методы
length
Свойство length (длина) является свойством каждого массива (это не метод).
Оно представляет количество элементов в массиве:
alert([0, 1, 2].length); // 3
Обратите внимание, что индексы массива начинаются с нуля. Поэтому длина мас-
сива всегда больше, чем последний индекс
concat
Метод concat возвращает объединение двух или более массивов. Чтобы исполь-
зовать его, сначала нужно создать два или более массива для объединения:
const arrl = ["aVbVc"];
const агг2 = [ d", e ’,”f"];
Затем создайте третий массив и присвойте ему значение arrl . concat (аг г2):
const аггЗ = arrl.concat(arr2); // аггЗ теперь: [ a"."b",“c“,*dn,"e","f”]
Обратите внимание, что в этом примере новый массив аггЗ содержит элементы
как из массива а г г 1, так и из массива а г г 2.
join и split
Метод join возвращает строку, которая содержит все элементы массива, разде-
ленные указанным разделителем. Если разделитель не указан, по умолчанию ис-
пользуется запятая.
Также существует метод split, который выполняет обратное действие: он рабо-
тает со строкой, разделяет ее на элементы на основе указанного разделителя и воз-
вращает массив, содержащий эти элементы. (Подсказка: split — это метод типа
string, а не массива.)
Чтобы использовать join, сначала создайте массив:
const abc = ["а", "b", "с");
Затем создайте новую переменную и присвойте ей значение abc. join():
const а = abc.join(); // "a,b,c"
Также можно использовать определенный разделитель:
// используем 'точку с запятой' и 'пробел' как разделитель
const b = abc.join("; "); // "а; Ь; с
Преобразуйте строку обратно в массив с помощью метода split
const а2 = a.split(“,''); //["а“, "Ь', с']
const Ь2 = b.splitC; “); // ["а", "Ь", ''с"]
push
Метод push добавляет один или более элементов в конец массива и возвращает
новую длину массива.
58
Массивы
"use strict";
const arr = [0, 1, 2, 3];
alerr ИГГ ) i; // 0, i, 2, з
const len = arr push (1CH3 1 ;
alert(leni i; // 5
alert! : arr} i; // 0. 1, 2, 3, 100
pop
Метод pop удаляет последний элемент массива и возвращает его:
"use strict ;
const arr = |0, 1, 2, 3];
alert(arr); // p, 1, 2, 3
const elem = arr.pop();
alert(elem); // 3
alert(arr); //0,1,2
Методы push и pop работают с концом массива, они обратны по своему действию.
unshift
Метод unshift добав.тяет один или более новых элементов в начало массива
и возвращает новую длину массива, Он работает, «сдвигая» каждый старый элемент
с его текущего индекса, добавляет новый элемент в индекс 0 и обновляет свойство
length массива. Этот метод похож на push, но работает с началом массива:
use strict';
const arr |0, 1, 2, 3 ];
alert(arr); // 0, 1, 2, 3
const len = arr .unshift(103);
alert(len); //5
alert(arr); // 130, 0, 1, 2, 3
shift
Метод shift удаляет первый элемент массива и возвращает удаленный элемент.
Он работает, «сдвигая» каждый старый элемент с его текущею индекса, обновляет
свойство length массива и возвращает старый первый элемент. Этот метод похож
на pop, ио работает с началом массива:
use strict";
const агг = [0, 1, 2, 3];
alert(arr); // 0, 1, 2, 3
const elem = arr.shift();
alert(e3em); // 0
alert(arr); //1,2,3
Методы unshift и shift работают с началом массива; они обратны по своему
действию.
См. также
MDN: Arrays (https://developer.mo^a.org/en-US/docs/Web/JavaScript/
Reference/Global_Objects/Array)
Даты
В JavaScript дата (Date) является объектом. Следовательно, она должна быть явно
создана с помощью оператора new.
Дата содержит значение, которое представляет количество миллисекунд, прошед-
ших с 1 января 1970 года по UTC. Стоит упомянуть, что она не содержит информации
о временной зоне. Тем не менее вы можете преобразовать ее в строку, соответствую-
щую любой произвольной временной зоне. Другие методы могут извлекать части,
такие как месяц или день недели, или вы можете использовать это число для любых
вычислений и многого другого.
Конструктор
Конструктор по умолчанию создает объект Date, соответствующий текущему мо-
менту времени на вашем компьютере:
const currentMilliSeconds = new Date(); // создает новый объект Date, соответствую-
щий текущему моменту
alert(currentMilllSeconds);
// неявное преобразование в строку
alert(currentMilliSeconds.toString()); // явное преобразование в строку
alert(currentMilliSeconos.valueOf());
// реальное значение
Вы можете передать параметры в конструктор для создания определенного объ-
екта Date:
// 1U00 мс = 1 секунда после начала "эпохи Javascript"
const pointInTime_1 = new i:ate(1000);
alert(pointInTime_1);
// начало последней минуты последнего века
const pointInTime_2 = new Date(1999, 11, 31, 23, 59);
alert(point!nTime_2);
Методы
Далее рассмотрим некоторые часто используемые методы объекта Date.
Статические методы
Date.now(): Возвращает количество миллисекунд, прошедших с 1 января
1970 года, 00'00:00 UTC, откалиброванное (плюс/минус несколько часов)
в соответствии с временной зоной вашего компьютера.
Date.UTC(<napaMerpbi>) : Возвращает количество милли-
секунд с 1 января 1970 года, 00:00:00 UTC.
Date, parse (text): Парсинг строк с помощью Date.parse()
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/
Reference/Global_Objects/Date#static_methods) настоятельно не
рекомендуется из-за различий и несоответствий в браузерах.
60
Даты
Методы экземпляра
• toISOString() : Возвращает строку в формате ISO 8601.
• getFullYear() : Возвращает полный 4-значный год.
• getMonth(): Возвращает текущий месяц. [О —11)
• getDate(): Возвращает день месяца. 11 —31]
• getDay (): Возвращает день недели. [О — 6]. Воскресенье — 0. остальные дни
недели принимают последующие значения.
• getHours(): Возвращает часы [0 — 23] в 24-часовом формате.
• getMinutes() : Возвращает минуты. |0 — 591
• getSeconds() : Возвращает секунды. [(. — 59]
• getTime(): Возвращает время в миллисекундах с 1 января 1970 года.
• valueuf(): Возвращает время в миллисекундах с 1 января 1970 года.
Эквивалентнг getTimeO.
• getTimezoneOffset() : Возвращает разницу в минутах между UTC
и локальным временем.
• setFullYear (year) : Устанавливает полный 4-значный год в объекте Date.
• setMonth(month, day): Устанавливает месяц и, опционально, день месяца,
'О' — январь,...
«Как целое число»
Дата может быть возвращена как целое числе- с помощью метода valueOf()
или путем добавления знака + перед конструктором, например, для использования
в качестве «зерна» для ГПСЧ (генератора псевдослучайных чисел) юш для выполне-
ния вычислений:
const dateAs!nteger_1 = new Cate().valueOf();
alert(dateAslnteger_l);
const dateAs!nteger_2 = +new Date(),
alert(dateAslnreger_2);
Временные зоны
Объект Date содержит только целое число (Integer). Он ничего не «знает» о вре-
менных зонах. Пока вы не указываете временные зоны в какой-либо форме, вы рабо-
таете в своей локальной временной зоне.
Но иногда необходимо учитывать временные зоны
// Пример 1
// Создание е UTC: 27 января, полночь
const date.1 = new Date(Date.UTC(2020. 00, 27, 0, 0, 0));
alert(date_1);
// отображение . другой временной зоне (Джакарта +7) ...
const jakartaTime = new Intl.DateTimeForniatl en-GB', { timeZone: 'Asia/Jakarta ,
dateStyle 'full', timeStyle- leng }).format(date_1);
alert(jakartalime),
// ... исходное значение не изменилось
alert(date_1);
// Пример 2
// предположим, что мы находимся в часовом поясе Ньы-Йорка (-5 относительно UTC)
const date_2 = new Date();
console.Log(date_2 toStringl));
II отображение в другой временной зоне (Лос-Анджелес -8 относительно UTC)
Новый API, Temporal
61
const laTime = new Inti .DateTi[reFarmat(' en-GB', { tmeZone: ' America/Los.Arigeles',
dateStyle: 'full', timeStyle: 'Jong }).format(date_2);
console.log(laTime);
// ... внутреннее значение не изменилось
console.log(Cate_2 toString());
Новый API: Temporal
Объект Date имеет некоторые несоотвегсгвня и недостатки,
например: слабая поддержка временных зон, отсутствие поддерж-
ки негригорианских календарей, отсутствие календарных функ-
ций и многое другое. Возможно, они будут исправлены в новом
API Temporal (https://tc39.es/proposal-temporaVdocs/index.html) в од-
ной из последующих версий JavaScript.
См. также
W3Schools: Методы объекта Date (https://www.w3schools.com/js/
js_date_methods.asp)
Регулярные выражения
Регулярное выражение (Regular Expression — RE или RegExp) — это шаблон, ко-
торый может соответствовать или не соответствовать заданной строке, напри-
мер (в псевдокоде): «одна цифра, за которой следует от одной до пяти букв». Строка
"3Stars" соответствует этому шаблону7, а строка Three Stars"—нет.
Регулярные выражения записываются с использованием собственного синтак-
сиса. Вышеуказанный псевдокод должен быть выражен как /\d\w{ 1,5}/, где ша-
блон заключен в слеши в начале и конце и содержит формальное описание для слов
цифра (\d),'буква (\w)h'ot одной до пяти' ({1,5}).
С точки зрения JavaScript RegExp — это тип данных, производный от Object,
Он имеет свои собственные конструкторы, методы и свойства. Однако их прямое
использование в форме объекта может быть не совсем понятным интуитивно. По-
скольку данная книга адресована начинающим в JavaScript, мы объясняем преиму-
щества и применение регулярных выражений в контексте строк, что является стан-
дартным слушаем использования. Также мы показываем только простые регулярные
выражения и основные аспекты.
Регулярные выражения чаще всего используются в сочетании с методами match
и replace строк.
Метод для строки match
Метод match принимает регулярное выражение и возвращает массив с совпада-
ющими строками:
use strict";
const myVar = "A short text";
// показать результат match()
alert(myVar.malch(/t t/)); // обратите внимание на слеши
// match() принимает регулярное выражение как строку вместо /.../)
alert(myVar.match("t t"));
// явный конструктор регулярного выражения
const re = new RegExp( “t t");
alert(myVar.maTch(re));
Принятие решений
Если метод match не находит совпадений в строке, он возвращает null. Посколь-
ку JavaScript интерпретирует null как false, результат можно использовать в ус-
ловном операторе if:
use strict";
const myVar = 'A short text";
if (myVar,match(/t t/)) {
alert("Bingo ");
} else {
alert("Bad luck.'');
}
Метасимволы
63
Метасимволы
Регулярные выражения становятся очень мощными благодаря использованию
метасимволов вместо конкретных символов. Метасимволы расширяют значение ре-
гулярных выражений различными способами: указывают классы символов, подста-
новочные знаки, квантификаторы, группы, обратные ссылки и многое другое.
Подстановочный знак
Вы можете использовать . (точку) в качестве подстановочного знака для любого
символа:
"use strict*:
const myVar - "A short text";
alert(myVar,match(/t..t/)); // text
Квантификаторы
Существует три квантификатора:
• 7 (вопросительный знак) указывает на ноль или одно вхождение пред-
шествующего элемента.
• * (звездочка) указывает на ноль или более вхождений предшествующего
элемента.
• + (плюс) указывает на одно или более вхождений предшествующего элемента.
"use strict";
const myvar = aaa bbb ccc 789";
alert(myVar.match(/bbb c?/)); // bbb c
alert(myVar.match(/bbb x?/)); // bbb
// одно 'c'
// ноль *x'
alert(myVar.match(/bbb c*/)); // bbb ccc // несколько * c'
alert(myVar.match(/bob c+/)); // bbb ccc // несколько c'
// к-мбинация пздстансвочного знака и квантификатора
alert(myVar.match(/bbb .*/)); // bbb ccc 789 // несколько произвольных символов
Модификаторы
Семантика регулярного выражения может быть изменена путем добавления од-
ного из модификаторов g, i или ш в конец (после второго слеша) регулярного выра-
жения.
• g (global) указывает, что должны быть возвращены все вхождения регу-
лярного выражения, а не только первое.
• i (ignore case) указывает, что регистр символов должен игнорироваться
• m (multiple lines) указывает, что регулярное выражение должно работать
с учетом переносов строк.
"use strict";
const myVar = 'A short text that contains 7 words.";
alert(myVar,match(/t t./g)); // t te, t th
alert(myVar.match(/SHORT/));
// null
alert(niyVar.match(/SHORT/i)); // short
64
Регулярные выражения
Классы символов
Некоторые важные классы символов (или типы символов) обозначаются следую-
щими обратными слешами:
• \w Буквенно-цифровой символ или
* \W Не буквенно-цифровой символ или
• \d Цифра
• \D Не цифра
• \s Пробельный символ (пробел, табуляция, новая строка, перевод страницы)
• \S Не пробельный символ
• \ЬГраница слова
'use strict";
const myVar = a+ а аЗ ";
alert(myVar.match(/a\w/)); //аЗ
alertjmyVar,match(/a\W/)); //a+
alert(myVar.match(/\d/)); //3
alert(myVar.match(/a\s/)); //a
alert(myVar .match(/aW/)); //a
Метод для строки replace
Метод replace возвращает новую строку, в которой регулярное выражение заме-
нено на заданную строку:
use strict";
const myStringl = "Hello world.";
const myString2 = myStringl.replace(/world/, "Tim');
alert(myString2); // Hello Tim.
Внешние ссылки
MDN: Regular
Expressions in
JavaScript -1
(http://developer.
mozilla.org/
en/JavaScript/
Guide/Regular_
Expressions)
MDN: Regular
Expressions in
JavaScript - 2
(https://dev eloper.
mozilla.org/en-
US/docs/Web/
JavaScript/
Reference/Global_
Objects/RegExp)
WBSchools:
JavaScript RegExp
Reference
(www.w3schools.
com/jsref/jsref_obj.
regexp.asp)
JavaScript RexExp
Tester
(www.regular-
expressions.info/
javascriptexample,
html) на regular-
express) ons.info
Операторы
Конкатенация строк
Оператор + действует двумя разными способами в зависимости оз типов ei о двух
операндов. Если один или оба из них являются строками, он действует как «конкате-
натор» строк. Если оба операнда числовые, он выполняет арифметическое сложение.
Пример конкатенации строк: "one " + ' world ' в результате дает "one world".
Если один из двух операндов не является строкой, он неявно преобразуется в строк}'
перед выполнением операции +:
"use strict";
// обычная конкатенация
const word.l = "one";
const word_2 = "world";
let result = word_l + " “ + word_2;
alert(result); // "one world'
// неявное преобразование типов
const ar г = [41, 42, 43];
result word_1 + arr + word_2; // сначала массив преобразуется в строку
alert(result); fl 'one4i,42.43world"
const x = 1;
result = x + word .2;
alert(result); // "Iworld'
Арифметические операторы
JavaScript поддерживает арифметические операторы +, *, /, % (остаток от деле-
ния) и ** (возведение в степень). Эти операторы работают так, как вы изучали в ма-
тематике. Умножение и деление выполняются перед сложением и вычитанием. Если
вы хотите изменить порядок выполнения операций, используйте скобки.
Примечание: в отличие от некоторых других языков, операция деления может
возвращать число с плавающей точкой — это не всегда целое число.
const a = 12 + 5; //17
const b = 12 - 5; //7
const c = 12 * 5, //60
const d = 12 / 5, //2.4 Деление возвращает число с плавающей точкой
const e = 12 % 5; //2 Остаток от деления 12 на 5 равен 2
const f = 12 - 2 * 5; // 2 Умножение выполняется первым
const 9 =(12 - 2) * 5; // 5b Скобки выполняются первыми
Некоторые математические операции, такие как деление на ноль, могут возвра-
щать «значения ошибок» — например, Infinity или NaN (не число). Результат опе-
ратора остатка от деления сохраняет знак первого операнда,
Операторы + и - также имеют унарные версии, где они действуют только на одну
переменную. В этом случае + возвращает числовое представление объекта, а - воз-
вращает его отрицательное значение:
66
Операторы
"use strict ;
const a = 42;
const b = +a; /7Ь равно 42
const с = -a; // с оаьно -42
Как уже упоминалось, + также используется как оператор конкатенации прок: если
любой из его аргументов является строкой или не является числом, все аргументы пре-
образуются в строки и объединяются. Все остальные арифметические операторы работа-
ют иначе — они пытаются преобразовать свои аргументы в числа перед вычислением:
"use strict";
const а = 42;
const b = "2";
const c = '3";
alertfa + b); // “422'' (строка)
alert(a * b); II 84 (число)
alert(b * c); // 6 (число)
Побитовые операторы
Существует семь побитовых операторов: &, |, Л, ~, >>, << и >>>. Эти операторы
преобразуют свои операнды в целые числа (отбрасывая дробную часть) и выполняют
указанные побитовые операции. Логические побитовые операторы &, | и А выполня-
ют операции И, ИЛИ и исключающее ИЛИ для каждого бита и возвращают результат.
Оператор ~ (НЕ) инвертирует все би гы в числе и обычно используется в сочетании
с логическими побитовыми операторами.
Два оператора сдвига битов,» и «, перемещают биты в одном направлении, что име-
ет эффект, аналогичный умножению или делению па степень дво1йси. Последний опера-
тор сдвига, »>, работает аналогично, но не сохраняет знаковый бит при сдвиге.
Эти операторы сохраняются для совместимости с другими языками программиро-
вания, но редко используются в большинстве программ на JavaScript.
Операторы присваивания
Оператор присваивания = присваивает значение переменной. Примитивные типы,
такие как строки и числа, присваиваются напрямую. Однако имена функций и объек-
тов являются лишь указателями на соответствующие функции или объект. В этом
случае оператор присваивания изменяет только ссылку на объект, а не сам объект.
Например, после выполнения следующего кода будет выведено "0, 1, 0", хотя
аггау_А был передан в alert, но аггау_В был изменен. Это происходит потому,
что они являются двумя ссылками на один и тот же объект:
"use strict';
const array_A = [0, 1, 2];
ccnst array.B = array.A;
array_B[2] = 0;
alert(array. A); // 0, 1, 0
Аналогично после выполнения следующего фрагмента кода х будет указывать
на пустой массив:
"use strict ;
ccnst z = [5];
const x « z;
z bop();
alert(x);
Операторы инкремента и декремента
67
Если результат любого из вышеуказанных арифметических или побитовых опе-
раторов должен быть присвоен первому операнду, можно использовать сокращен-
ный синтаксис. Обьедините оператор, например, +, с оператором присваивания =,
получив+=. Например, х = х + 5 можно сократить до х += 5.
Сокращенный синтаксис оператора/присваивания выглядит следующим образом:
Арифметические Логические
Например, частое использование += в цикле for.
"use strict";
const arr = [1, 2, 3];
let sum = i-1;
tor (let i = 8; i < arr.length; i++) {
sum += arr[i]; // то же, что: sum = sum + arr[i];
)
alert(sum);
Операторы инкремента и декремента
Операторы инкремента и декремента являются особыми формами арифметиче-
ских операторов: ++ и а++ увеличивает а и возвращает старое значение а. ++а
увеличивает а и возвращает новое значение а Оператор декремента действует ана-
логично, но уменьшает переменную.
Например, следующие операции выполняют одну и ту же задачу:
"use strict";
let а = 1;
alert(a); // 1
а = а + 1;
alert(a); //2
а += 1;
alert(a); // 3
а++;
alert(a); //4
++а;
alert(a); // 5
alert(a++); // показывает 5 снова
alert(a); // тем не менее 'а было увеличено до 6
Пре- и пост-инкрементные операторы
Операторы инкремента могут быть записаны до или после переменной. Позиция
определяет, являются ли они пре-инкрементными или пост-инкрементными опера-
торами соответственно Это влияет на выполнение операции.
68
Операторы
"use strict ;
// инкремент происходит до присваивания а к b
let а = 1;
let о = ++а; // а = 2, Ь = 2;
// инкремент происходит к с после прис-.аивания с к О
let с = 1;
let d = C++; // с = 2, d = 1;
Из-за возможной путаницы в поведении пре- и пост-инкрементных операторов
код можно будет читать, если избегать использования операторов инкремента:
"use strict ;
// инкремент происходит до присваивания а к b
let а = 1;
а += 1 ;
let b = а; //а=2, Ь=2;
// инкремент происходит к с после присваивания с к d
let с = 1;
let d = с;
с += 1;
// с = 2, d = 1;
Операторы сравнения
Операторы сравнения определяют, соответствуют ли два операнда заданному ус-
ловию Они возвращают true или false
Что касается операторов «равно» и «не равно», следует быть внимательным. Опе-
ратор == отличается от ===. Первый пытается адаптировать типы данных двух опе-
рандов друг к другу, а затем сравнивает значения. Второй сравнивает как типы, так
и их значения и возвращает t rue только в том случае, если тип и значение идентич-
ны. 3 -= "0003 вернет true, а 3 === "3" вернет false.
Оператор Возвращает Примечания
== true, если два операнда равны Может изменить тип одного из операндов (например, строку на число).
=== true, если два операнда строго равны Не изменяет типы операндов. Возвращает true, если они одного типа и значения.
1 = true, если два операнда не равны Может изменить Tim одного из операндов (например, строку на число).
! == true, если два операнда не строю равны Не изменяет типы операндов. Возвращает true, если они различаются по типу или значению.
> true, если первый операнд больше второго
Логические операторы
69
Оператор Возвращает Примечания
>= true, если первый операнд больше или равен второму
< true, если первый операнд меньше второго
< = true, если первый операнд меньше или равен второму
Рекомендуется испо.гьзовать строгие версии операторов (===
и ! ==), так как простые версии могут приводить к странным и не-
интуитивным ситуациям (https://dorey.github.io/JavaScript-Equality-
ТаЫе/).
Например:
0 == ' ' 0 == 'б' false == 'false false =» '0 false =- undefined false == null null == undefined // true // true // false (''Boolean to string'1) // true (''Boolean to string' ) // false // false ('‘Воjlean to null ') // true
Хотя, возможно, вы ожидаете:
0 === " // false
0 === '0' // false
false === 'false' // false
false === '0 // false
false === undefined // false
false === null // false
null =- = undefined // false
Логические операторы
Логические операторы — это и, или и не, которые записываются как &&, | | и !.
Первые два принимают но два булевых операнда каждый. Третий принимает один
операнд и возвращает его логическое отрицание.
Операнды — это булевы значения или выражения, которые вычисляются в буле-
во значение:
"use strict*;
const а = 0;
const Ь = 1;
if (а === 0 && b === 1) { // логическое 'и'
alert("a is 0 AND b is T');
}
if (a === 1 || b === 1) { // логическое 'или'
alert("a is 1 OR b is 1");
}
70
Операторы
Операторы && и | | являются операторами «короткого замыкания»’ если резуль-
тат гарантирован после вычисления первого операнда, второй операнд не вычис-
ляется Благодаря этому оператор && также известен как оператор-страж, а опера-
тор | | — как оператор по умолчанию:
"use strict ;
// объявляем myArray' без инициализации
let myArray;
// ошибка времени выполнения!
if (myArray length > 0) {
alert(“The length of the array is: ' + myArray.length);
}
// ошибки нет, потому что часть после '&& не будет выполнена1
if (myArray && myArray.length > 0) {
alert("The length of the array is: " + myArray.length);
}
Оператор ! определяет инверсию заданного булева значения: true становится
false, a false становится true.
Примечание: JavaScript представляет false как булево значение fa Ise. число 0,
NaN, пустую строку или встроенные типы undefined или null. Любое другое значе-
ние рассматривается как true
Чти касается приоритета трех операторов, ! вычисляется первым, затем && и, на-
конец, | |.
b && ! с
I I I
I И. J
Подробнее о связи между' приоритетом и «коротким замы-
канием» объясняется на MDN (https://developer.mozilla.org/en-US/'
docs/Web/JavaScript/Reference/Operators'Operator_Precedence#short-
circuiting).
Другие операторы
Оператор ? : (также называемый тернарным оператором) является сокращени-
ем для оператора if Сначала он вычисляет часть перед вопросительным знаком.
Затем, если результат истинный, вычисляется и возвращается часть между вопроси-
тельным знаком и двоеточием, иначе — часть после двоеточия:
const target = (а == b) ? с d;
Однако будьге осторожны при его использовании. Хотя вы можете заменить гро-
моздкие и сложные цепочки if/then/else тернарными операторами, это может
быть не лучшей идеей. Например, вы можете заменить:
Другие операторы
71
if (р && q) {
return а;
} else {
if (г != s) {
return b;
} else {
if (t || !v) {
return c;
} else {
return d;
}
}
на;
return (p &Я q) 9 a
: (r != s) 9 b
: (t || !v) 9 c
: d;
Приведенный выше пример является плохим стилем программирования. Когда
другие люди (или даже вы сами) будут редактировать или поддерживать ваш код, его
будет гораздо сложнее понять и работать с ним. Вместо этого лучше сделать код бо-
лее понятным. Например, можно убрать избыточную вложенность условий:
if (р && q) {
return а;
}
if (г != s) {
return b;
}
if (t || !v) {
return c;
} else {
return d;
}
delete
delete obj . x удаляет свойство x из объекта ob j.
Ключевое слово delete удаляет свойство из объекта. Оно удаляет как значе-
ние свойства, так и само свойство После удаления свойство нельзя использовать
д'1 тех пор, пока оно не будет добавлено снова. Оператор delete предназначен
для использования со свойствами объектов. Он не имеет эффекта па переменные
или функции.
new
new cl создает новый объект типа cl. Операнд cl должен быть функцией-кон-
структор ом.
instanceof
о instanceof с проверяет, был ли объект о создан конструктором с.
72
Операторы
typeof
typeof x возвращает строку, описывающую тип х. Могут возвращаться следую-
щие значения;
Тип Возвращаемое значение
boolean "boolean"
number "number"
string "string"
function "function"
undefined "undefined"
null "object"
другие (массив (array),...) "object"
См. также
MDN. Операторы (https://developer.mozilla.org/en-US/docs/Web/
JavaScript/Reference/Operators/)
Управляющие структуры
Большинство языков программирования состоят из «строительных блоков», таких
как токены (ключевые слова, переменные, операторы и т. д.), выражения (например,
myArray. length + 1), инструкции (разделенные ;), блоки {...}, функции и моду-
ли. На первый взгляд, выполнение программы следует последовательности инструк-
ций сверху вниз. Однако почти во всех случаях необходимо, чтобы программа выпол-
нялась не в строгом порядке написанных инструкций. Вместо этого некоторые части
должны выполняться только при определенных условиях, а другие могут быть про-
пущены и выполнены при других условиях. Или может возникнуть необходимость
в повторяющемся выполнении некоторых частей. Другие часто могут выполняться
параллельно и синхронизироваться позже Или функция из другого модуля должна
вычистить значение, прежде чем можно будет выполнить следующую инструкцию.
В этой иерархии «языковых блоков» термин «блок» (block) является ключевым
для понимания потока выполнения программы. В JavaScript блок — это последова-
тельность из нуля или более инструкций (или меньших блоков), заключенных в фи-
гурные скобки { // нуль или более инструкций }. Конструкции языка, которые
мы обсуждаем здесь, вызывают или повторяют блоки.
if / else
Инструкция if / else (да, это одна инструкция, даже если она содержит другие
инструкции в своих блоках) вызывает выполнение одного из двух блоков в зависи-
мости от результата вычисления условия. Результат вычисления возвращает логи-
ческое значение (boolean). Если оно равно true, выполняется первый блок; если
false — второй блок. Соответственно, другой блок припускается:
if (condition) {
// блок инструкций
} else {
// блок инструкций
}
Часть else является необязательной, то есть можно использовать if без части
else и ее блока:
if (condition) {
// блок инструкций
}
Пример:
"use strict";
const а = 3;
const b = "3";
if (a == b) {
alert( The two variables contains the same value, but may have different data
types.");
} else {
alert(”The two variables contain different values.");
}
74
Управляющие структуры
// пример без else'
const с = 6 / 2;
if (а === с) {
alert("The two variables contains the same value and are of the same data type. );
}
Если один из двух блоков содержит ровни ОДНУ инструкцию, фигурные скобки
можно опустить. Однако для ясности кода рекомендуется использовать синтаксис
с фигурными скобками:
//то же, что и выше; но этот сокращенный синтаксис не рекомендуется.
use strict ;
const а = 3;
const b = "3";
if (a == b) alert("The two variables contains the same value, but may have different
data types ");
else alert('The two variables contain different values.');
const c - 6 / 2;
if (a === c) alert("The two variables contains the same value and are of the same
data type ");
Во многих случаях ситуация требует более сложных решений, чем простое аль-
тернативное условие true/false. Папример, может потребоваться определить, яв-
ляется ли число отрицательным, нулевым или положительным. В таких случаях ре-
шение может выглядеть так:
‘use strict";
const х = 3;
if (x < 0) {
alert("The number is negative.");
} else {
// x равно или больше 0
if (x === 0) {
alertf'The number zero.");
} else {
alert('The number is positive.");
}
}
Этот код можни немного сократить без потери ясности. Поскольку первый блок
else содержит только одну инструкцию, а именно второй if, можно опустить его
фигурные скобки и объединить первый е Ise и второй if в одной строке:
"use strict";
const х = 3;
if (х < 0) {
alert("The number is negative.");
} else if (x === a) {
alert("The number is zero.");
} else {
alert('The number is positive.");
}
Этот стиль программирования является понятным и часто используется в ситуа-
циях, когда у вас есть управляемое количество вариантов или когда необходимо при-
нимать решения с несколькими переменными.
switch
75
switch
Если количества решений значительно возрастает, код становится более по-
нятным, если использовать инструкцию switch вместо длинного списка условий
else if.
Инструкция switch вычисляет выражение и направляет поток выполнения
в зависимости от сравнения его результата с метками, указанными после ключе-
вого слова case:
"use strict";
const myVar = a";
// вычисление может принимать как простые переменные, так и сложные выражения
switch (myVar.totlpperCasef)) {
case "A":
// -
break;
case "B“:
// ..
break;
default: // аналог 'else' без дополнительных 'if'
//
break;
}
Если результат вычисления совпадает с одной из меток, JavaScript выполняет сле-
дующие инструкции до следующего break или до конца всей инструкции switch
Если ни одна из меток не совпадает, выполнение продолжается с метки default,
или, если она отсутствует, пропускает инструкцию switch целиком.
Метки могут быть литералами или выражениями; например, case (2 + 1).
toString() : допустимо.
Как только достигается инструкция break, выполнение switch завершается.
Обычно она появляется в конце каждого case, чтобы предотвратить выполнение
кода следующих case Однако ее можно опустить, если вы намеренно хотите выпол-
нить их в дополнение к текущим. В следующем примере один и тот же код будет вы-
полнен для i, равного 1,2 или 3:
"use strict";
const i = 2;
switch(i) {
case 1:
case 2:
case 3:
// ..
break;
case 4:
//
break;
default:
// ..
break;
}
Поскольку выражение для вычисления, а также метки могут быть сложными вы-
ражениями, можно создавать очень гибкие конструкции:
76
Управляющие структуры
"use strict ;
const i = 2;
switch(true) { // в данном примере это постоянное значение
case (i < 10):
alert('one digit");
break;
case (i >= 10 && i < 100):
alert(' two digits'');
break;
default:
// -
break;
}
Ключевое слово continue не применяется к инструкции switch.
try / catch / finally
Если существует вероятность возникновения ошибки во время выполнения про-
граммы. вы можете «поймать» эту ошибку и выполнить осмысленные действия
для обработки ситуации. Например, сетевое соединение или база данных могут стать
недоступными; ввод пользователя может привести к делению на ноль и т. д.:
try {
// критический блок, где могут возникнуть ошибки
} catch (err) {
// блок для обработки ьозможных ошибок. Обычно не выполняется.
} finally {
// блок, который будет выполнен в ЛЮБОМ случае
}
use strict";
ccnst х = 15;
let average;
try {
// блок с критическими выражениями
x = x + 5;
average = x / 0;
alert("The average is: " + average);
} catch (err) {
// блок для обработки возможных ошибок
alert( 'Something strange occurs. The error is: " + err);
} finally {
// блок, который будет выполнен в ЛЮБОМ случае
alert('End of program.");
}
Если одно из выражений в критическом блоке (блок try) вызывает ошибку
во время выполнения, выполнение оставшихся выражений пропускается. Вместо
этого выполнение переходит к блоку catch В конце выполняется блок finally.
Обратите внимание, что блок finally выполняется в любом случае, независи-
мо от того, произошла ли ошибка во время выполнения или нет. Это правило так-
же применяется, если критический блок или блок catch выполняют выражение
return.
throw
77
throw
В приведенном выше примере движок JavaScript сам выбрасывает исключение.
В других ситуациях движок JavaScript действует тем или иным образом, но вы може-
те захотеть, чтобы это обрабатывалось иначе. Например, в случае деления на ноль
движок не выбрасывает ошибку; он присваивает результату значение Infinity
и переходит к следующему выражению. Если вы хотите другого поведения, вы може-
те создавать и выбрасывать исключения самостоятельно:
"use strict";
const х = 15;
let average;
try {
11 блок с критическими выражениями
average = x / и.
II или: const z = "abc"; average = z / 0;
if (average === Infinity || Number.isNaN(average)) {
// Выбросьте собственное исключение с любым текстом
throw “Error during division. The result is: 11 + average;
}
alert("The average is: + average);
} catch (err) {
// блок для обоаботки возможных ошибок
alert('Something strange >ccurs. The error is: + err);
} finally {
// блок, который будет выполнен в ЛЮБОМ случае
alert("End of program.");
}
Если возникает исключение (сгенерированное движком JavaScript или вашей про-
граммой) и оно не перехватывается блоком catch, скрипт завершается или — если
это функция — возвращает управление вызывающей функции. Обработка ошибки
может быть реализована там или в одной из функций, которые были вызваны;
"use strict";
const answer = prompt("How old are you’");
const age = Number(answer);
if (isNaN(age)) {
throw answer + " cannot be converted to a number.";
// Скрипт завершается с этим сообщением (это не функция)
}
alert("Next year you will be + (age +1));
Циклы
Циклы и итерации — это другие случаи, когда последовательный поток выраже-
ний управляется окружающими языковыми конструкциями. Это описано далее.
См. также
MDN: Управление потоком программы и обработка ошибок
(https^/developer.moziila.org/en-US/docs/Web/JavaScript/Guide/ControL
flo wjind^error_handli ng)
Циклы
JavaScript поддерживает повторяющееся выполнение блоков кода с помощью
ключевых слов f о г и while. Подобное поведение предлагает метод fо гЕ ach для типа
данных Array (и аналогичных типов дашгых).
for (;;) {}
Синтаксис оператора for: for (<начальное выражение*; ^условие*; <за-
ключительное выражение*) { <блок* }. Он выполняется по следующим правилам:
1. Начальное выражение выполняется ровно один раз для всего оператора
for. Обычно ини объявляет и инициализирует одну или несколько
переменных—часто это числа с целыми значениями (Int). Иногда объявление
переменных происходит выше оператора for
2. Условие оценивается. Если оно возвращает true, выполняется шаг 3. Если
оно возвращает false, оператор for завершается.
3. Блок кода выполняется.
4. Завершающее выражение выполняется. Обычно оно увеличивает
или уменьшает переменную, которая является частью условия.
5. Цикл повторяется с шага 2.
for (let i = 0; i < 10; i++) {
// блок операторов
}
Пример: показать последовательность четных чисел, возведенных в квадрат
(степень 2); показать сумму чисел от 0 до 10;
use strict";
const upperLimit = 10;
let sum = 0;
let tmpString =
for (let i = 0; 1 <= upperLimit; i++) {
sum = sum + i;
if (i % 2 === 0) {
tmpString += i*i + “; "
}
}
alert ( The sum is: " + sum + ". The square numbers are: " + tmpString);
Необязательные части синтаксиса
Начальное выражение, условие и завершающее выражение являются необяза-
тельными. Если вы опустите одну или несколько из них, ваш скрипт должен выпол-
нять другие полезные операторы для управления циклом. Некоторые примеры:
"use strict";
// бесконечный цикл, если не завершить его с помощью 'break' (см. ниже)
for (;;) {
// ...
Break;
}
continue / break
79
const answer = prompt ("With which start value shall the loop begin?1');
let i = Number(answer);
for (; i >- 0 && i < 10; i++) {
// начальное значение вычисляется выше цикла
}
for (let i = и; i < 10; ) {
// ...
if (true) { // произвольное другое условие для управления инкрементом
1++;
}
}
Вложенность
Циклы for могут быть вложенными. Вы можете использовать второй (или «вну-
тренний») цикл внутри блока первого (или «внешнего») цикла:
"use strict";
const maxlnner = 19;
const maxOuter = 4;
let myString =
for (let o=1; о <= maxOuter; o++) {
myStnng = "";
// Будьте осторожны. Легко перепутать переменные внутреннего и внешнего циклов.
for (let 1=1; i <= maxlnner; i++) {
myString = myString + o*i + ", ";
}
alert(myString);
}
Такая вложенность циклоп также возможна во всех нижеоштсанных конструк-
циях.
continue / break
Иногда нужно выполнить только часть блока. Это можно реализовать с помощью
одного или нескольких операторов if / else. Если это уместно, такие условные
операторы можно сократить с помощью ключевого слова continue. Если достигает-
ся continue, остальная часть блока пропускается, и выполняется завершающее вы-
ражение (шаг 4):
"use strict";
for (let i = 9; i <= 6; i++) {
if (i === 5) {
continue; // пропустить оставшуюся часть блока
}
alert(i); // 0. 1, 2, 3, 4, 6
}
Этот пример очень прост. Он пропускает нижнюю часть блока для случая, когда
i равно 5. Конечно, это можно выразить по другому Более реалистичный пример —
это цикл по результатам поиска в базе данных, который пропускает части сложной
обработки строк с определенным статусом
Ключевое слово break похоже на continue, но более жесткое. Оно пропускает
не только оставшуюся часть блока, но и завершает весь цикл:
“use strict";
for (let i = 9; i <= 6; i++) {
80
Циклы
if (i === 5) {
break; // завершить цикл
)
alert(i);
}
Реалистичный сценарий — это цикл по результатам поиска в базе данных, где со-
единение с базой данных прерывается в середине цикла.
Вы можете использовать continue и break во всех формах обсуждаемых здесь
вариантов циклов.
do 0 while ()
Синтаксис оператора: do { <блок> } while (<условие>). Он выполняется
по следующим правилам:
1. Блок выполняется. Поскольку это самый первый шаг. блоквыполняется хотя
бы один раз. Это полезно, если вы хотите быть уверены, что что-то произойдет
при любых обстоятельствах.
2. Условие оценивается. Если оно возвращает true, выполняется шаг 1.
Если оно возвращает false, цикл завершается. Обратите внимание, что нет
конкретной части, где можно управлять переменной, которая проверяется
в условии. Это должно быть сделано где-то в блоке среди других операторов.
"use strict";
let counter = 100;
do {
counter++;
alert(counter); // .. или какой-то лог
} while (counter < 10);
white () {}
Синтаксис while (<условие>) { <блок> } очень похож на предыдущий do
{ <блок> } while (<услсвие>). Единственное отличие в том, что условие прове-
ряется до, а не после блока.
for (х in Object) {}
Эта языковая конструкция предназначена для итерации по свойствам объекта.
Ее синтаксис for (<переменная> in <объект>) { <блок> }. Переменная получает
ключ всех свойств объекта но очереди. Для каждого из них блок выполняется один раз:
'use strict";
const myObj = {firstName Marilyn", familyName- ’Monroe", born: 1953};
for (const key in myObj) {
alert(key); // firstName, familyName, born
// alert(myObj[key]); // если вы хотите увидеть значения
}
Массивы являются специализированными объектами. Поэтому возможно ис-
пользовать f or. .in для массивов. Ключи для массивов — это целые числа, начиная
с 0, и именно это извлекается из массива:
"use strict";
const myArray = [“certo", "uno", "dos", "tres"];
for (const key in myArray) {
alert(key); // 0, 1, 2, 3
// alert(myArray[key]); // если вы хотите увидеть значения
}
for (x of Array) {}
81
Массивы также принимают нечисловые ключи, например,
myArray! "four" ] = " cuat го" ;.Цикд for. .in обрабатывает такие
нечисловые ключи—в отличие от цикла for. .of, описанного ниже,
и в отличие от традициошгого цикла for, описанного в начале.
См. также: MDN: for.in (hitps://developer.mozilla.org/en-US/docs/
Web/Java,Script/Reference/Statements/for...in)
for (x of Array) {}
Эта языковая конструкция предназначена для итерации по массиву. Ее синтак-
сис: for (<переменная> of «итерируемый объект>) { <блок> }. Переменная
получает все значения массива по очереди. Для каждого из них блок выполняется
один раз.
Это определение звучит похоже на определение for.. in. Но есть значительные
различия:
• Возвращает значения, а не ключи или индексы массива.
• Работает только с итерируемыми объектами (Array, Map, Set, . . .). Тип
данных object не является итерируемым.
• Работает только с числовыми ключами. Нечисловые ключи или индексы
игнорируются.
"use strict";
const myArray = ["cero", uno", "dos1, tres ];
myArrayf1 four"] = cuatro";
for (const myVaiue of myArray) {
alert(myValue); /7 cero, uno, dos, tres. Нет 'cuatro’, потому что ключ - строка.
См. также: MDN: for .of (https://developer.mozilla.org/en-US/docs/ >
Web/JavaScript/Reference/Statements/for...of)
for..in vs. for..of
Различия между' двумя языковыми конструкциями суммированы в примере:
"use strict";
const myObj = {^irstName: "Marilyn , familyName: ‘Monroe”, born: 1953};
const myArray = ["cero", “uno", "dos1, "tres’];
myArrayj'four"] = ‘cuatro”;
// for..of не разрешен для объектов; толоко for..in возможен,
for (const x of myObj) {}; // ошибка
for (const x in myArray) {
aiert(x); // 8, 1, 2, 3, tour
}
for (const x of myArray) {
alert(x); // cero, uno, dos, tres. HET cuatro1
}
Метод Object.entries()
Если вы ищете цикл, который обрабатывает как ключи, так и значения объекта, есть
более простой метод, чем комбинация for.. in с myObj [ key ]. Tim данных Ob ject
предлагает метод ent r ies (), который возвращает массив. Каждый элемент этого мае-
82
Циклы
сива содержит массив с двумя значениями: ключ свойства и значение свойства. Дру-
гими словами, возвращаемое значение метода entries() — это двумерный массив.
И, как обычно с массивами, вы должны использовать его в сочетании с f о г. .of:
use strict";
const myOb] = {firstName: Marilyn'', familyName- Monroe', born: 1953};
const myArray = ["cere", "uno', "dos", "tres"];
HiyAr ray [ "four" ] = "cuatro";
for (const [key, val] of Object entries(myObj)) {
alert(key + ' / ' + val);
}
for (const [key, val] of Object entries(myArray)) {
alert(key + ' / ' + val); // four / cuatro включен
}
Подсказка: методы Object. entries (), как и следующие методы Array.
f">rEach(), не являются «основными» языковыми элементами, такими как клю-
чевые слова или конструкции for. .in или for. .of. Это методы типов данных
Object и Array соответственно.
Метод Array.forEach()
Тип данных Array предоставляет метод forEach(). Он выполняет итерацию
по элементам массива, возвращая каждый элемент по очереди. Интересный момент
заключается в том, что он принимает функцию в качестве аргумента. Это отличает
его от циклов for и while. Такие функции часто называют функциями обратного
вызова (callback function).
Вызов метода очень прост: myAr г ay for Each (ту Function). Возможно, запутан-
ной частью является то. что вызовы функций могут быть сокращены различными
способами.
Первый пример показывает явный вызов функции. Он определяет функцию
myFunction, которая также принимает один аргумент. Когда myFunction вызыва-
ется с помощью forEach(), следующий элемент массива передается в качестве ар-
гумента в myFunction:
"use strict";
II определение функции (Функция не вызывается здесь1)
function myFunction(element) {
alert("The element of the array is: ' + element)
}:
// тестовый массив
const myArray = ['a', 'b , 'c*];
// итерация no массиву и вызов функции для каждого элемента массива
myArray.forEach(myFunction);
Следующие примеры показывают некоторые сокращения синтаксиса вызова
функции:
"use strict";
// синтаксис стрелочной функции' (arrow function)
ccnst myFunction =
(element) => {
alert("The element of the array is: " + element)
};
См также
83
// тот же код без переносов строк:
// const myFunction = (element) => {alert( "The element of the array is. " + element)};
const myArray = I a', b , 'c'];
myArray.forEach(myFunction);
"use strict";
const myArray = I 'a', ’b', ' c'],
// Определение функции непосредственно в качестве аргумента forEach().
// Такие функции называются 'анонимными' функциями (anonymous functions).
myArray.forEach((element) => {alert('The element of the array is: + element)});
"use strict";
const myArray = [ a’, b', 'c'J;
// в простых случаях дополнительные синтаксические элементы являются необязательными
myArray.forFach(eLement => alert("The element of the array is: “ + element));
Выбор синтаксиса зависит от ваших предпочтений.
Во многих случаях вызываемая функция выполняет побочные эффекты, такие
как легирование. Для вычисления значений пп всем элементам массива необходимо
использовать технику замыканий (closures). В следующем примере переменная sum
определена не во внешнем контексте, а внутри анонимной функции:
"use strict";
const myArray = [3, 0, -1, 2];
let sum = 0;
myArray.forEach(element => sum = sum + element);
alert(sum);
В целом для метода forEach() применяются следующие правила:
• Метод может использоваться для итерируемых объектов, таких как Array,
Map, Set. Тип данных Object не является итерируемым.
• Метод выполняет итерацию только по тем элементам, которые имеют
числовой ключ, что является обычным случаем для массивов.
См. также
MDN: forEachO
(https://developer.
mozilla.org/en-US/
do cs/W eb/J a vaScript/
Reference/Global_
Objects/Array/
forEach)
MDN Итеративные
методы
(https ://developer.
mozilla.org/en-US/
docs/Web/JavaScript/
Reference/Global_
Objects/А rrayfriterative.
methods)
MDN: Циклы и итерации (https://developer.mozilla.org/en-US/
docs/"Web/JavaScript/Guide/Loops_and_iteration)
Функции
Функция — это блок кода, который решает определенную задачу и возвращает ре-
шение в вызывающую инструкцию. Функция существует в собственном контексте. Та-
ким образом, функции разделяют крупные программы на более мелкие «кирпичики»,
которые структурируют как программное обеспечение, так и процесс разработки:
// определение функции
function <function_name> (<pararieters>) {
<function_Dody>
}
// вызов функции
<variable> = <function_name> (<arguments>);
JavaScript: поддерживает парадигму функционального программирования. Функ-
ции являются типом данных, производным от Object; они могут быть привязаны
к переменным, передаваться в качестве аргументов и возвращаться из других функ-
ций, как и любой другой тип данных.
Объявление
Функции могут быгь созданы гремя основными способами.
Традиционный способ:
"use strict";
// традиционное обьявление (или ‘определение )
function duplication(p) {
return р + "! “ + р + "!";
}
// сыЗОВ функции
const ret = duplicaticn(“Go‘);
alert(ret),
Создание через переменную и выражение:
"use strict";
// присвоение функции переменной
let duplication = function (р) {
return р + “! " + р +
};
const ret = duplication("Go');
alert(ret);
Создание через оператор new (этот вариант немного громоздкий):
"use strict";
// использование конструктора 'new'
let duplication = new Function ("p",
' return p + 1! ' + p + '!1");
const ret = duplication("Go');
alert(ret);
Ьызов
85
Вызов
Для объявления функций мы рассмотрели три варианта Для их вызова также су-
ществует три варианта. Объявления и вызовы независимы друг от друга, и вы може-
те произвольно комбинировать их.
Традиционный вариант вызова использует имя функции, за которым следуют
круглые скобки (). Внутри скобок указываются аргументы функции, если они есть:
‘'use strict";
function duplication(p) {
return p + “! " + p + "!";
}
// традиционный способ вызова
const ret = dupiication( Go );
alert(ret);
Если скрипт выполняется в браузере, есть еще две возможности. Они используют
объект window, предоставляемый браузером:
"use strict*;
function duplication(p) {
return p + “! " + p + "I";
}
// через call'
let ret = duplicatjon.call(window, "Go );
alert(ret);
// через apply
ret = duplication.apply(’Aindow, ["Go ]);
alert(ret);
Подсказка: если вы используете имя функции без круглых скобок (), вы получи-
те саму функцию (скрипт), а не результат вызова:
"use strict";
function duplication(p) {
return p + "I " + p +
}
alert(duplication); // 'function duplication (p) { ... }
Поднятие (Hoisting)
Функции подвержены механизму «поднятия» (hoisting). Этот механизм автоматиче-
ски переносит ибъявлеште функции в верхнюю часзъ ее области видимости. Как след-
ствие вы можете вызывать функцию выше (в исходном коде) ее объявления:
"use strict";
// использование функции выше (в исходном коде) ее объявления
const ret = duplication "Go );
alert(ret);
function duplication(p) {
return p + "! " + p + "!";
}
86
Функции
Немедленно вызываемая функция
(Immediately Invoked Function)
До сих пор мы рассматривали два отдельных этапа: объявление и вызов функции.
Существует также синтаксический вариант, который позволяет объединить оба эта-
па. Он характеризуется использованием круглых скобок вокруг объявления функ-
ции, за которыми следуют (), чтобы вызвать это объявление:
"use strict";
alert( // alert для отображения результата
// объявление плюс вызов
(function (р) {
return р + "I " + р + ;
})('Go") // ('Go"): вызов с аргументом "Go'
);
alert(
// то же самое с использованием стрелочной1 синтаксиса
((р) => {
return р + "! “ + р + ...;
})( Gooo')
);
Этот синтаксис известен как «немедленно вызываемое функ-
циональное выражение» (Immediately Invoked Function Expression,
IIFE) (https://developer.mozilla.org/en-US/docs/Glussary/IIFE).
Аргументы
Когда функции вызываются, параметры из фазы объявления заменяются аргумен-
тами вызова. В приведенных выше объявлениях мы использовали имя переменной р
в качестве имени параметра. При вызове функции мы в основном использовали ли-
терал "Go" в качестве ар1уменга. Во время выполнения этот аргумент заменяет все
вхождения р в функции. Приведенные выше примеры демонстрируют эту технику.
Передача по значению (Call-by-value)
Такие замены выполняются по значению (https://developer.
m02illa.0rg/en-US/d0cs/Web/JavaScrip1/Reference/Functi0ns#passing_
arguments), а не по ссылке.
Копия исходного значения аргумента передается в функцию.
Если это скопированное значение изменяется внутри функции,
исходное значение за пределами функции не изменяется:
use strict";
// есть один параметр 'р
function duplication(p) {
// В этом примере мы изменяем значение параметра
р = "NoGo";
alert("In function: " + р);
return р + "! " + р + "!" ;
};
Let х = "Go";
const ret = duplication(x);
// f идно ли здесь изменение аргумента, сделанное в функции’3 Нет.
alert("Return value- " + ret + " Variable: " + x);
Аргументы
87
Для объектов (всех неиримитивиых типои данных) эта передача по значению
имеет — возможно — удивительный эффект. Если функция изменяет свойство объ-
екта, это изменение также видно снаружи:
"use strict";
function duplication(p) {
p a = 2; // изменяем значение свойства
p b = xyz'; // добавляем СВОЙСТВО
alert("In function: " + JSON stringify(p));
return JSON.stringify(p) + "! " + JSON.stnngify(p) + “I";
};
let x = {a: 1);
alert("Object: " + JSON.stringify(x));
const ret = duplication(x);
// Зидно ли здесь изменение аргумента, сделанное в функции? Да.
alert("Return value: " + ret + Object: ” + JSON stringify(x));
Когда пример выполняется, он показывает, что после вызова duplication из-
менения, сделанные функцией, видны не только в возвращаемом значении. Также
свойства исходного обьекта х изменились. Почему так происходит? Это отличается
от поведения с примитивными типами данных? Нет.
Функция получает копию ссылки на объект. Следовательно, внутри функции ссы-
лаются на тот же объект. Сам объект существует толью один раз, но есть две (иден-
тичные) ссылки на объект. Не имеет значения, изменяются ли свойства обьекта од-
ной ссылкой или другой.
Еще одно следствие — и это может быть интуитивна понятно, как и с примитив-
ными типами данных, — что изменение самой ссылки, например, путем создания
нового объекта, не будет видно во внешней процедуре. Ссылка на новый объект со-
храняется в копии исходной ссылки. Теперь у нас есть не только две ссылки (с разны-
ми значениями), но и два объекта.
1 “use strict";
2
3 function duplication р) {
4
5 // изменяем ссылку, создавая новый объект
6 р = {};
7
р.а = 2; II изменяем значение свойства
9 p.b = 'xyz'; // добавляем свойство
10 alert("In function: " + JSON.stringify(p));
11 return JSON.stringify(p) + "! " + JSON.stringify(p) + .....;
12 };
13
14 let x = {a: 1};
15 alert("Object: + JSON.stringify(x));
16 const ret = duplication(x);
17
18 // видны ли здесь изменения аргумента, сделанные в функции9 Нет.
19 alert( 'Return value: + гет + " Object. " + JSON.stringify(x));
88
Функции
Примечание 1: название этой техники передачи аргументов
не используется единообразно в разных языках. Иногда это назы-
вается вызовом по соиспользованию (call-by-sharing). В Википедии
есть обзор (https://en.wikipedia.Org/wiki/Evaluation_strategy#Strict_
binding, strategies).
Примечание 2: описанные последствия передачи аргументов
в JavaScript сопоставимы с последствиями использования ключе-
вого слова const, которое объявляет переменную как константу.
Такие переменные нельзя изменить. Тем не менее, если они ссы-
лаются на объект, свойства объект а можно изменить.
Значения по умолчанию
Если функция вызывается с меньшим количеством аргументов, чем она содер-
жит параметров, лишние параметры остаются undefined. Но вы можете определить
значения по умолчанию для этого случая, присвоив значение в сигнатуре функции.
Отсутствующие параметр]»! получат эти значения по умолчанию:
use strict";
// две почти идентичные функции; различается только сигнатура
function fl(а. b) {
alert("The second parameter is: " + b)
};
function f2(a, b = 10) {
alert("The second parameter is: " + b)
};
// одинаковые fi(5); fl(5, 1Й0); вызовы; разные результаты // undefined // 100
(2(5); f2(5, 100); // 10 // 100
Переменное количество аргументов
Для некоторых функций «нормально», что они вызываются с разным количе-
ством ар]ументов. Например, рассмотрим функцию, которая отображает имена.
firstName и familyName должны быть указаны в любом случае, но также возмож-
но, что нужно отобразить academic! itle или tit leOf Nobility. JavaScript предла-
гает различные возможности для обработки таких ситуаций.
Индивидуальные проверки
«Обычные» параметры, а также дополнительные параметры, можно проверить,
чтобы определить, содержат ли они значение или нет:
use strict ;
function showName(firstName, familyName, academicTitle, titleOfNobility) {
"use strict”;
// обработка збязательных параметре-.
let ret =
if (!firstName || 'familyName) {
return first name and family name must be specified";
}
Аргументы
89
ret = firstName + ", " + familyName;
// обработка необязательных параметр' и
if (academicTitle) {
ret = ret + ", " + academicTitle;
}
if (titleOfNobility) {
ret = ret + ", " + titleOfNobility;
}
return ret;
}
alert(showName("Mike’, ’Spencer", PhD."));
alert(showName("Tom"));
Каждый отдельный параметр, который может быть не указан, должен быть про
верен индивидуально.
Оператор rest
Если обработка необязательных параметров структурно идентична, код можно
упростить, используя синтаксис оператора rest — обычно в сочетании с циклом.
Синтаксис этой функции состоит из трех точек в сигнатуре функции — как в синтак-
сисе расширения (spread syntax).
Как это работает? В процессе вызова функции движок JavaScript объединяет пе-
реданные необязательные аргументы в один массив. (Обратите внимание, что вызы-
вающий скрипт не использует массив.) Этот массив передается функции в качестве
последнего параметра:
"use strict";
// три точки (...) вводят синтаксис rest1
function stio»vName( firstName, familyName, ...titles) {
// обработка обязательных параметров
let ret = "";
if (IfirstName || ’familyName) {
return "first name and family name must be specified";
}
ret = firstName + ’, + familyName;
// обработка необязательных параметров
for (const title of titles) {
ret = ret 1- ", " + title;
}
return ret;
}
alert(snowName("Mike", 'Spencer", "Ph.D , ’Duke"));
alert(showName("Tom"));
Третий и все последующие аргументы вызова собираются в один массив, который
доступен в функции в качестве последнего параметра. Это позволяет использовать
цикл и упрощает исходный код функции.
Ключевое слово arguments
В соответствии с другими членами семейства языков программирования С
JavaScript предлагает ключевое слове arguments внутри функций. Это объект, по-
хожий на массив, который содержит все переданные аргументы вызова функции.
Вы можете перебирать его или использовать его свойство length.
90
Функции
Его функциональность сопоставима с синтаксисом rest. Основное отличие за-
ключается в том, что arguments содержит все аргументы, тогда как синтаксис rest
не обязательно влияет на все аргументы:
"use strict";
•function sho,vName(firstName, familyName, academicTitles, titlesOfNobility) {
// обработка ВСЕХ паоаметр-'В с помощью одного ключевого слова
for (const arg of arguments) {
alert(arg);
}
}
snowName("Mike", 'Spencer", Ph.D", "Duke);
Возврат (return)
Цель функции — предоставить решение конкретной задачи. Это решение возвра-
щается в вызывающую программу с помощью оператора return.
Его синтаксис: return <выражение>, где <выражение> является необязательным.
Функция выполняется до тех пор, пока не достигнет такого оператора return
(или пока не возникнет необработашюе исключение, или пока не будет достиг-
нут последний оператор). <выражение> может быгь простой переменной любого
типа данных, например return 5, или сложным выражением, например return
mySt ring . length, или может быть полностью опущено: return.
Если в операторе return отсутствует <выражение> или если оператор return во-
обще не достигнут, возвращается undefined:
"use strict ;
function duplication(p) {
if (typeof p === object ) {
return; // возвращаемое значение: 'undefined
}
else if (typeof p === string ) {
return p + "! " + p + "! ;
}
// неявный возврат 'undefined
}
let arg = [ Go", 4, {a: 1}];
for (let 1=0; i < arg.length; i++) {
const ret = duplication(arg[i]);
alert(ret);
}
Стрелочные функции (=>)
Стрелочные функции представляют собой компактную аль-
тернативу традиционному синтаксису функций, описанному
выше. Они сокращают некоторые элементы языка, опускают дру-
гие и имеют лишь несколько семантических отличий (https://
developer.niozilla.org/en-US/docs/Web/JavaScnpt/Reference/Funcnons/
Arrow_funclions) по сравнению с оригинальным синтаксисом.
Рекурсивные вызовы
91
Они всегда анонимны, но могут быть присвоены переменной:
"use strict";
// оригинальный традиционный синтаксис
function duplication(p) {
return р + “I " + р + "!";
}
// 1. удаляем ключевое слово 'function и имя функции
// 2. еводим '=>'
// 3. удаляем return'; последнее значение автоматически возвращается
(Р) => {
р + "! " + р + "!"
)
// удаляем { }, если только один оператор
(р) => р + "!'' + р + !"
// Убираем скобки у параметра, если он только один
//-----------------------------
р => р + "! " + р + // вот и все!
И -----------------------------
alert(
(р => р + "! " + р + "!")( 'Go')
Вот еще один пример с использованием массива. Метод f о rEach проходит по мас-
сиву и передает каждый элемент массива в качестве ар]умента е стрелочной функ-
ции. Стрелочная функция выводит е вместе с коротким текстом:
"use strict";
const myArray = ['а', b', 'с'];
myArray.forEach(e => alert( The element of the array is: ” + e));
В других языках программирования концепция стрелочных функций может быть
известна вод терминами анонимные функции (anonymous functions) или лямбда-вы-
ражения (lambda expressions).
Рекурсивные вызовы
Функции могут вызывать другие функции. В реальных приложениях это часто
встречается.
Особый случай возникает, когда функция вызывает саму себя. Это называется рекур-
сивным вызовом (recursive invokation). Конечно, это подразумевает риск бесконечных
циклов. Чтобы избежать этой проблемы, необходимо изменить что-то в аргументах.
Обычно необходимость в таких рекурсивных вызовах возникает, когда приложе-
ние работает с древовидными структурами, такими как спецификация материалов,
DOM-дерево или генеалогическая информация. Здесь мы рассмотрим простую мате-
матическую задачу вычисления факториала.
Факториал — это произведение всех положительных целых чисел, меныпих
или равных определенному числу, обозначаемому как п1. Например, 4 1 =4*3*
2 * 1 = 24. Это можно решить с помощью цикла от 1 до п, но существует также ре-
курсивное решение. Факториал числа п — это уже вычисленный факториал числа
п -1, умноженный на п. или в формулах: п! = п * (п-1)!. Эта идея приводит к со-
ответствующему рекурсивному построению функции:
92
Функции
"use strict ;
function factorial(n) {
if (n > 0) {
const ret = n * factorial(n-1);
return ret;
} else {
// n = 0; 0' равно 1
return 1;
}
}
const n = 4;
alert(factorial(n));
Пока n > 0, функция factorial вызывается снова, нс- на этот раз с аргументом
п-1. Когда достигается п = 0, это первый случай, когда функция f actorial не вы-
зывается снова. Она возвращает значение 1, которое умножается на следующее боль-
шее число из предыдущего вызова factorial. Результат умножения возвращается
в предыдущий вызов factorial, и так далее.
См. также
MDN: Функции
(hnps://developcr.
moziUa.org/en-US/docs/
Web/JavaScript/Guide/
Functions)
MDN: Остаточные па-
раметры
(https://developer.
moziHa.org/en-US/
docs.'Web/JavaScript/
Referen се/Functions/
rest.parameiers)
Замыкания (Closures)
Замыкание (Closure) — это техника, при которой функция связывается (замыкает-
ся) с окружающими ее переменными, лексическим окружением (lexical environment).
Обычно замыкания реализуются в функциональных языках программирования, та-
ких как JavaScript, где они поддерживают каррирование (Currying).
Лексическое окружение (Lexical environment)
Сначала покажем доступ функции к ее лексическому окружению. Само по себе это
еще не замыкание:
"use strict";
function IncrementByCertainValue(param) {
return param + certainValue;
}
let certainvalue = 1Э;
alert(incrementByCertainValue(8)); // 18
certainvalue = 100;
alert(incrementByCertainValue(8)); // 108
ФункцияшсгетепСВуСегХаХпУаЗиеувеличиваетсвойпараметрна значение пе-
ременной certainvalue. Поскольку incrementByCertainValue и certainvalue
определены в одном блоке, функция имеет доступ к этой переменной. Каждый раз,
когда функция вызывается, она читает переменную и использует ее для вычисления
возвращаемого значения.
Замыкание (Closure)
Чтобы расширить приведенный пример до замыкания, необходимо объединить
(внутреннюю) функцию с доступом к переменным ее лексического окружения —
обычно это другая функция — и сохранить это состояние, возвращая эту внутрен-
нюю функцию:
1 "use strict' ;
2
3 function incrementByCertainValue(param) {
. // объявляем функцию, которая выполнит работу. (Только объявление,
пока не вызывается.)
5 const add = function (certatnValue) {
, // доступ к param' из лексического окружения и к параметру
'certainValue'
7 return param + certainvalue;
8 }
9 return add;
10 }
11
94
Замыкания (Closures)
12 const incrementB/Five = incrementByCertainValue(5);
13 alert(incrementByFive(8)); // 13
14
15 const incrementBySix = incrementByCertainValue(6);
16 a]ert(incremenrBySix(8)); // 14
17
18 alert(incrementByFive(l0l); // 15
Функция IncrementByCertainValue (внешняя):
• Содержит параметр param,
• Определяет (внутреннюю) функцию add, которая принимает еще один
параметр се г ta inValue
• В дополнение к своему параметру (в!гутренняя) функция имеет доступ (как
обычно) к своему лексическому окружению, где определен param.
• Возвращает (внутреннюю) функцию,
Пока что здесь только объявления, и никакого исполняемого кода.
Когда переменная incrementByFive объявляется в строке 12, она инициали-
зируется возвращаемым значением функции incrementByCertainValue(5).
Это ключевой момент, где код выполняется, и техника замыкания вступает в дей-
ствие. Внутри incrementByCertainValue значение 5 известно как параметр/
переменная param. Затем создается функция add, использующая param из сво-
его лексического окружения. Эта функция add принимает один параметр, кото-
рый должен быть передан из вызывающей программы позже. Оператор return
в incrementByCertainValue возвращает эту функцию add, которая связала зна-
чение ’ 5' в своем теле. Обратите внимание, что имя функции add произвольно
и не видно за пределами incrementByCertainValue.
Когда IncrementByCertainValue вызывается второй раз с аргументом ' 6', зна-
чение ' 6 связывается с отдельной, второй функцией.
См. также
MDN1 Замыкания
(https://developer.
mozilla.org/en-US/
docs/W eb/Ja v aScript/
Closures)
Википедия: Замыкания
(https://en.wikipedia.org/
wiki/Closure_(computer_
programming)
Асинхронность (async)
Без использования специальных ключевых слов и техник движок JavaScript вы-
полняет инструкции одну за другой в последовательности, в которой они написаны
в коде. В большинстве случаев это необходимо, потому что результаг одной строки
используется в следующей:
"use strict";
/* Строка 1 */ const firstName = 'Mahatma";
/* Строка 2 */ const familyName = Gandhi";
/* Строка 3 */ const completeName = firstName + " " + familyName;
Строки 1 и 2 должны быть полностью выполнены перед тем. как можно будет
выполнить строку 3. Это обычное последовательное поведение. Однако бывают си-
туации, когда следующим инструкциям не нужно ждать завершения текущей. Или,
например, вы ожидаете, что какое-то действие будет выполняться долго, и хот ите
сделать что-то другое в это время. Таксе параллельное выполнение может значи-
тельно сократить общее время отклика. Это становится возможным благодаря тому,
что современные компьютеры имеют несколько процессоров и способны выполнять
несколько задач одновременно. В приведенном выше примере строки 1 и 2 могут вы-
полняться параллельно. Более того, клиент-серверная архитектура делегирует зада-
чи на несколько серверов
Типичные ситуации — эго длительные обновления базы данных, обработка боль-
ших файлов или ресурсоемкие вычисления. Но даже для таких простых вещей, как от-
рисовка HTML-страницы, браузер обычно выполняет несколько задач одновременно.
Однопоточность
Пи своей природе JavaScript является однопоточным, и весь код JavaScript выпол-
няется в одном потоке. Это включает ваш исходный код программы и сторонние би-
блиотеки, которые вы подключаете в своей программе. Когда программа выполняет
операцию ввода-вывода для чтения файла или сетевого запроса, это блокирует ос-
новной поток111.
Чтобы достичь одновременного выполнения задач, браузеры, сервис-воркеры
(service workers), библиотеки и серверы предоставляют дополнительные интерфей-
сы. Их основное применение — это разблокировка выполнения HTTP-запросов и за-
просов к базе данных; меньшая часть сосредоточена на ресурсоемких вычислениях.
На уровне языка JavaScript существует три техники для достижения асинхронно-
сти — тою, что «ощущается» как одновременность.
• Функция обратного вызова (callback function)
• Промис (Promise)
• Ключевые слова async и await
Базовая техника — это использование функций обратного вызова. Этот термин ис-
пользуется для функций, которые передаются в качестве аргумента другой функции,
особенно (но не только) для функций, которые реализуют асинхронное поведение.
Промис (Promise) представляет собой окончательное завершение или сбой асин-
хронной операции, включая ее результат. Он управляет дальнейшей обработкой по-
сле завершения таких асинхронных операций.
96
Асинхронность(async)
Поскольку оценка промисов с использованием .then и .catch может привести
к трудночитаемому коду (особенно если они вложены), JavaScript предлагает клю-
чевые слова async и await. Их использование создает хорошо слруктурированный
код, сравнимый с try . . catch .. finally в традиционном JavaScript. Однако
они не реализуют дополнительные функции. Вместо этого «под капотом» они осно-
ваны на промисах.
Строго последовательно? Нет
Чтобы продемонстрировать, что код не всегда выполняется в строго последова-
тельном порядке, мы используем скрипт, который содержит ресурсоемкие вычисле-
ния внутри более или менее большого цикла. В зависимости от вашего компьютера
ин мижет выполняться несколько секунд:
1 'use strict";
2
3 // функция с ресурсоемкими вычислениями
4 async function func_async(upper) {
5 await null; // (1)
6 return new Promise(function(resolve, reject) { // (2)
7 console.log("Starting loop with upper limit: " + upper);
8 if (upper < r?) {
9 // произвольная проверка для генерации ошибки
10 reject(upper + is negative Abort.");
11 }
12 for (let i - 0; i < upper; i++) {
13 // произвольная математическая функция для тестирования
14 const s = Math sin(i); // (3)
15 }
16 console.log("Finished loop for: " + upper);
17 resolve('Computed. " + upper);
18 })
19 }
20
21 const doTask = function(arr) {
22 for (let i = 0; i < arr.length; i++) {
23 console.log("Function invocation with number; ' + arr[i]);
24 func_async(array11i])
25 then((msg) => console.log('Ok. " + msg))
26 .catch((msg) => console.log('Error, " + msg));
27 console.log("Behind invocation for number' " + arr[i]);
28 }
29 }
30
31 const arrayl = [3234567890. 10, -30];
32 doTask(array1);
33 console.log('End of program Really'5');
Callback
97
Ожидаемый вывод:
Function invocation with number, 3234567840
Behind invocation for number: 3234567890
Function invocation with number; 10
Behind invocation for number: 1и
Function invocation with number' -30
Behind invocation for number: -30
End of program. Really9
Starting loop with upper limit 3234567890
Finished loop for: 3234567898
Starting loop with upper limit' 10
Finished loop for: 10
Starting loop with upper limit. -30
Finished loop for: -30
Ok. Computed 3234567898
Ok. Computed 10
Error. -30 is negative. Abort.
• Ядро асинхронной функции func_async представляет собой цикл, в котором
выполняется математическое вычисление J(3j строка 14J. Время выполнения
цикла зависит от переданного параметра.
• Возвращаемое значение func.async — это не просто значение, а промис
(Promise)[(2) строка 6].
• Функция func_async вызывается в doTask один раз для каждого элемента
переданного массива [(4) строка 24].
• Из-за асинхронной природы func_async функция doTask выполняется
полностью до того, как начнет выполняться func_async! Это можно
наблюдать по выводу программы.
• Выражение await null [(1) строка 5] является фиктивным вызовом. Оно
приостанавливает выполнение func_async, давая doTask возможность
продолжить выполнение. Если удалить это выражение, вывод будет другим.
Вывод: чтобы сделать функцию действительно асинхронной, необходимы оба
ключевых слова — async в сигнатуре функции и await в теле функции.
• Если у вас есть инструмент для детального наблюдения за работой компьютера,
вы можете заметить, что три вызова func_async не выполняются
одновременно на разных ядрах процессора, а выполняются последовательно
(на том же или на разных ядрах).
Callback
Передача функции в качестве параметра в (асинхронную) функцию — это ори-
гинальная техника в JavaScript. Мы демонстрируем ее назначение и преимущество
с помощью предопределенной функции setTimeout. Она принимает два параметра.
Первый — это функция обратного вызова (callback), о которой мы говорим Второй —
число, указывающее количество миллисекунд. через которое функция обратного вы-
зова будет вызвана:
"use strict";
function showMessageLater() {
setTimeout(showMessage, 3000); // н миллисекундах
}
function showMessage() {
alert("Gcod morning.");
}
98
Асинхронность (async)
showMessage();
// немедленный вызии
shoA'MessageLater(); // вызо! ' sbowMessage' через 3 секунды
Если showMessage вызывается, она выполняется мгновенно Если вызывается
showMessageLater. она передает showMessage в качестве функции обратного вы-
зова в setTimeout, которая выполняет ее с задержкой в 3 секунды.
Промис (Promise)
Промис отслеживает, была ли (асинхронная) функция успешно выполнена
или завершена с ошибкой, и определяет, что произойдет дальше, вызывая либо
.then,либо .catch.
Промис находится в одном из трех состояний:
• Pending (Ожидание): Начальное состояние, до того как будет «resolved»
(выполнено)или «rejected» (отклонено).
• Resolved (Выполнено): После успешного завершения функции был вызван
resolve.
• Rejected (Отклонено): После завершения функции с ошибкой был вызван
reject.
"use strict ;
// здесь у нас только определение!
function demoPronnse() {
// Оператор 'return' выполняется немедленно, и вызывающая программа
// продолжает свое выполнение Но значение 'return остается undefined до тех пор,
// пока не будет вызван 'resolve' или 'reject'.
return new Pronise(function(resolve, reject) {
11
H выполнение некоторых длительных действий, например,
// доступ к базе данных
И
const result = true; // для примера
if (result === true) {
resolve(Demo worked ");
} else {
reject("Demo failed.");
demoPromise() И вызов demoPromise'
,then((msg) => console.log(1 Ok: " + msg))
catch((msg) => console.log("Error: ' + msg));
console.log(''End of script reached. But the program is still running.");
Ожидаемый вывод:
End of script reached, hut the program is still running.
Ck Demo worked.
Когда вызывается demo Promise, она создает новый промис и возвращает его. За-
тем выполняется длительное действие, и в зависимости от результата вызывается
resolve или reject.
Далее (в то время как вызывающий скрипт выполняет другие действия) либо
функция . then (), либо . catch () после вызова demoPromise выполняется. Эти две
функции принимают (анонимную) функцию е качестве параметра. Параметр, пере-
даваемый в анонимную функцию,является значением Promise.
async/await
99
.then( ( msg ) => console.log( Ok: + rrsg) )
Illi II III
I | ।— параметр —1 ।----- тело функции ----1 | |
III II
| ।----------- анонимная функция --------------1 |
I I I
1------ параметр функции then()-------------------J
I----------------- функция then() --------------------
Обратите внимание, что последний оператор скрипта был выполнен ранее.
Многие интерфейсы библиотек, API и серверных функций определены и реа-
лизованы как функции, возвращающие промис, аналогично приведенной выше
demoPromise. Пока вам не нужно создавать собственные асинхронные функции,
вам не нужно создавать промис. Часто достаточно вызвать внешний интерфейс и ра-
ботать только с .then или .catch (или с async и await).
async/await
Ключевое слово await заставляет движок JavaScript выполнить скрипт, указан
ный после await, полностью, включая часть с new Promise, прежде чем выпол-
нить следующую инструкцию. Таким образом, с точки зрения вызывающего скрипта
асинхронное поведение устраняется. Функции, содержащие await, должны быть по-
мечены в своей сигнатуре ключевым словом async.
"use strict";
11 то же, что и выше
function demoPromise() (
return new Promise(function(resolve, reject) {
const result = true; // для примера
if (result === true) {
resolve( Demo worked."),
} else {
reject("Demo failed.");
}
})
}
// функция с вызовом 'demoPromise
// ключевое слово async' необходимо, чтобы разрешить использование await' внутри
async function start() {
try {
// исггльзуем 'await', чтобы дождаться завершения ’demoPrcmise'
// перед выполнением следующей инструкции
const msg = await demoPromisef);
// без await', 'msg содержит Promise, нс без
// сообщения со успехе или ошибке
console.log( Ok: " +msg);
} catch (msg) {
console.log('Error. " + msg),
}
}
start();
console.log("End of script reached End of program7");
Использование async и await позволяет работать с традиционным оператором
try и catch вместо then и. catch.
100
Асинхронность(async)
Реалистичный пример
Мы используем свободно доступный демо-ЛР1 https://
jsonplaceholder.typicode.com/.
Он предоставляет небольшое количество тестовых данных
в формате JSON.
use strict ;
async function getUserData() {
// fetch() “ это асинхронная функция Web API. Она возвращает promise
await fetch( https://jsonplaceholder.typicode.com/users')
// для использования ‘response см.: https://developer.mozilla.org/en-US/docs/
Web/APl/Pesponse/json
// ' .]son()' читает поток ответа
then(!response) => { return response.json() })
// в данном случае 'users' - это массив объектов (в формате JSON)
.then!(users) => {
console log(users); // все данные массив из 1@ элементов
// проходим по десяти элементам массива
for (const user of users) {
console.log(user name + " / " + user.email);
1
})
catch((err) => console. log(' Some errcr iccurred: ' + err message));
//тоже самое c try / catch'
async function getllserData_tc() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
console.log(users);
console.log(users[0].name);
for (const user of users) (
console log(user.name + " / " + user.email);
}
) catch (err) {
console.log!'Some error occurred: ' + err.message);
}
}
getUserData();
getUserData_tc();
Шаги примера:
1 . await fetch() : Получает данные пс указанному URL. Часть await
гарантирует, что скрипт не продолжит выполнение до тех пор, пока все
данные не будут получены.
2. j son () читает поток, содержащий результирующие данные.
3. Результирующие данные представляют собой массив из 10 элементов.
Каждый элемент имеет формат JSON, например:
{
"id : 1,
"name : "Leanne Graham",
"username : Bret'",
"email' Sincere@april.biz ,
"address": {
'street . 'Kulas Light',
suite': "Apt. 556',
См также
101
"city': "Gwenborough",
"zipcode : "92998-3874",
"geo': {
lat": *-37.3159",
"Ing": "81,1496"
}
},
"phone": "1-770-736-8831 x56442',
"website": "hildegard.org",
"company": {
"name1: 'Ronaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs“: "harness real-time e-markets"
}
}
В качестве примера скрипт выводит в консоль полные данные и некоторые их
части.
Примечание: вероятно, вы столкнетесь с ошибкой CORS
(htips://developer.moziUa.org/en-US'docs/Web/HTTP/CORS), если ис-
пользуете произвольный URL.
См. также
Процессы и потоки
(в Node.js)
(https://www.
digit alocean.
com/community/
tutorials/how-to-
use-multithreadiiig-
in-node-
jsfrunderstanding-
processes-and-
threads)
Промисы и 'async'
(в Node.js)
(https://www.
geeksforgeeks.org/
difference-between-
prom ise-an d -a sync-
a wait-in-no de-js/)
MDN: async
(https://developer,
mozilla.org/en-
US/docs/Web/
JavaScript/
Reference/
Statements/async
function)
MDN: Fetch API
(https://developer.
mozilla.org/en-US/
docs/Web/API/Fetch
API/Using_Fetch)
Ссылки
1, Скрытые потоки в Node.js (hi tps://www. digitalocean,
com/community/tutorials/how-to-use-multithreading-in-node-
js#understanding-hidden-threads-in-node-js)
Объектно-ориентированное
программирование
Объектно-ориентированное программирование (ООП) — это парадигма проек-
тирования программного обеспечения, которая впервые появилась в 1%0-е годы
и получила популярность в 1990-е годы. Они стремится к модульности, повторному
использованию, инкапсуляции и сокрытию состояния (данных) и поведения (функ-
ций), проектированию в иерархии обобщения, наследования и многого другого.
Оно позволяет компонентам быть максимально модульными. В частности, когда
создается новый тип объекта, ожидается, что он будет работать без проблем при раз-
мещении в другой среде или новом программном проекте. Преимущества этого под-
хода заключаются в сокращении времени разработки и упрощении отладки, по-
скольку вы повторно используете программный код, который уже был проверен.
Этот подход «черно! о ящика» означает, что данные поступают в объект, а другие дан-
ные выходят из объекта, но то, что происходит внутри, не требует вашего внимания.
Со временем были разработаны различные техники для реализации ООП. Наибо-
лее популярными из них являются классовый и прототипный подходы.
Классовый подход в ООП
Классы — это шаблон, который определяет все аспекты (состояние, а также поведе-
тше) группы структурно идентичных объектов. Шаблон называется классом, а объек-
ты —экземплярами этого класса. Популярные представители семейства языков С. осо-
бенно Java, C++ и С#, реализуют ООП с использованием этого классового подхода.
Прототипный подход в ООП
В проготипном подходе каждый объект хранит свое состояние и поведение. Кро-
ме того, у него есть прототип (или null, если он находится на вершине иерархии).
Такой прототип — это указатель на другой, более общий объект. Все свойства ссы-
лочного объекта также доступны в ссылающемся объекте. Классы не существуют
в проготипном подходе.
ООП в JavaScript: «Два пиджака на одно тело»
Одним из краеугольных камней JavaScript является предоставление объектов
в соответствии с правилами прототипного ООП. Объекты состоят из свойств, кото-
рые представляют собой пары «ключ/значение», содержащие данные, а также мето-
ды. Одним из таких свойств всегда является свойство прототипа_proto_. Оно ука-
зывает на родительский объект и таким образом реализует связь:
// связи реализуются с помощью свойства _proto__'
let parent = [];
let child = {
name: Joel',
__protc__: parent,
};
console.log(ODject.getPrototypeOf(child)); // Array []
ООП в JavaScript: «Два пиджака на одно тело»
103
Если запрошенное свойство отсутствует в каком-либо объекте, движок JavaScript
ищет его в родительском объекте, «дедушке» и так далее. Это называется цепочкой
прототипов.
Все э го одинаково применимо как к пользовательским объектам, т ак и к систем-
ным объектам, таким как массивы или даты.
Начиная с EcmaScript 2015 (ES6J, синтаксис предлагает ключевые слова, такие
как class или extends, которые используются в классовых подходах. Несмотря
на то. что такие ключевые слова были введены, основы JavaScript не изменились: эти
ключевые слова приводят к прототипам так же, как и раньше. Они являются «син-
таксическим сахаром» и компилируются в традиционную технику прототипов.
В итоге синтаксис JavaScript предлагает два способа выразить объектно-ориен-
тированные функции, такие как наследование, в исходном коде: «классический»
и «классовый» стили. Несмотря на разный синтаксис, техники реализации отлича-
ются лишь незначительна.
Классический синтаксис
С первых дней JavaScript определял отношение «родитель'потомок» объектов
с помощью механизма «прототипа». Если это явно не указано в исходном коде, это
происходит автоматически. Классический синтаксис хорошо это демонстрирует.
Чтобы явно определить отношение «родитель/потомок» двух объектов, следует
использовать метод setPrototypeOf, чтобы установить прототип объекта на дру-
гой объект. После выполнения метода все свойства, включая функции, родительско-
го объекта становятся известными дочернему объекту:
1 <1 DOCTYPE html>
2 <html>
3 <head>
4 <script>
5 function go() {
6 "use strict";
7
8 const adult = {
9 familyName: "McAlister ,
10 showFamily: function() {return "The family name is: " +
11 this . familyName;}
12 };
13 const child = {
14 firstName: "Joel",
15 Kindergarten: House of Dears'
16 };
17
18 // 'familyName и 'showFamilyf)' здесь не определены!
19 alertfchild.firstName + " " + child.familyName);
104
Объектно-ориентированное программирование
2й // устанавливаем предполагаемую цепочку прототипов
21 Object.setPrototypeOf(child, adult);
22 // или child.__prcto____ = adult;
23
24 alert(child.firstName + " " + child.familyName);
25 alert(child showFamilyO);
26 }
27 </script>
28 </head>
29
Зи <body id="body">
31 <butron onclick- go() >Rur. the demo</button>
32 </body>
33 </html>
Объект adult содержит familyName и функцию showFamily. На первом этапе
они неизвестны в объекте child После выполнения setPrototypeOf они стано-
вятся известны, потому что прототип child больше не указывает на стандартный
Ob j ect, а указывает на adult.
Следующий скрипт демонстрирует цепочку прототипов. Он начинается с поль-
зовательских переменных myArray и theObject. myArray — это массив с тремя
элементами. Операция присваивания в строке 6 устанавливает theObject в тот же
массив. Цикл показывает прототип theObject и присваивает следующий уровень
цепочки прототипов ему. Цикл завершается, когда достигается верхний уровень ие-
рархии. В этом случае прототип равен null.
1 function go() {
2 "use strict";
3
4 // определяем массив с тремя элементами
5 const myArray = [0, 1, 2];
6 let theObject = myArray;
7
8 do {
9 // показываем прототип объекта
console.log(Ooject.getPrototypeOf(theObject)); // Array[],
Object{...}, null
11 // или; console.log(theObject.__proto___);
12
13 // переходим на следующий уровень вверх
14 theObject = Ooject getPrototypeCf(theObject);
15 } while (theObject);
16 }
Как известно, свойства — это пары «ключ/значение». Следовательно, можно на-
прямую использовать значение свойства prototype для идентификации и манипу-
лирования прототипами. Интересно, что имя ключа — не prototype, а___proto__.
Это показано в строке 11. Тем не менее мы рекомендуем игнорировать эту тех-
ник}1 11 и использовать методы API для манипулирования прототипами, такие как
Object.getPrototypeOf, Object.setPrototypeOf и Object.create.
Синтаксис «классов»
105
Синтаксис «классов»
Скрипт определяет два класса. Adult и Child, с некоторыми внутренними свойства-
ми, одно из которых — метод. Ключевое слово extends объединяет два класса исрар
хически. После этого в строке 21 создается экземпляр с помощью ключевого слова new:
1 <IDOCTYPE html?
2 <html>
3 «head?
4 «script?
5 function go() {
6 "use strict";
7
8 class Adult {
9 constructor(familyName) {
10 this.familyName = familyName;
11 }
12 showFamily() {return "The family name is; " + this.familyName;}
13 }
14 class Child extends Adult {
15 constructor(firstName, familyName, kindergarten) {
16 super(familyNume);
17 this.firstName = firstName;
18 this .kindergarten = kindergarten;
19 }
20 }
21
22 const joel = new Childf' Joel", "McAlister", "House of Dwars');
23 alert(joel.firstName + " " + joel.familyName);
24 alert(joel.showFamily());
25 }
26 «/script?
27 «/head?
28
29 «body id«"body"?
30 «button onclick="go()"?Run the demo«/butcon>
31 «/body?
32 </html>
Свойство familyName и метод showFamily определены в классе Adult.
Но пни также известны в классе Child
Обратите внимание, чти это классовое наследование в JavaScript реализовано по-
верх классического прототипного подхода.
См. также
MDN. ООП в JavaScript (hnps:/./developer.mozilla.org/en-US/docs/
Learn/JavaScript/Objects/Object-oriented_programming)
Классическое ООП
Сердце объектно-ориентированного подхода в JavaScript — это связанный список
объектов, где каждый объект выступает в качестве прототипа для своего преемника.
Это становится очевидным при использовании классического синтаксиса,
Конструкция
Существуют различные синтаксические способы создания объектов. Они не иден-
тичны, но даже при рассмотрении их внутренней работы можно заметить лишь не-
значительные различия в их семантике. Все варианты создают набор пар «ключ/зна-
чение — свойства». Этот набор свойств составляет объект.
1 'use strict";
2
3 // создание через литералы
4 const obj_1 = {};
5 obj_1 property_1 = "1";
6 alert(obj_1.property.!);
7
f const obj.la = {property_1a: '1a"};
9 alert(obj_1a.prooerty_1a);
10
11
12 // создание через опеоатор ‘new
13 const obj_2 = new Object();
14 obj_2.property_2 = "2" ;
15 alert(obj_2 property_2);
16
17 const obj_2a = new Object({property_2a: "2a"});
1b alert(obj_2a.property_2a);
19
20
21 // создание через метод 'Object.create'
22 const obj_3 = Object.create({});
23 obj_3 property_3 = "3";
24 alert(obj_3.property_3);
25
26 const obj_3a = Object. create({property_3a: "3a"});
27 alert(obj_3a property_3a),
Три языковые конструкции- литерал, new и Object .create —создают простые
или сложные объекты. Такие объекты могут быть впоследствии расширены путем
присвоения значений дополнительным свойствам.
Конструкция
107
Функции
Часть «значение» в парах «ключ/значение» может содержать не только значения
примитивных типов данных. Также возможно, что они содержат функции. (Когда
функции являются частью значения свойства, они называются методами.)
1 "use strict";
2
3 // исполвзонэние синтаксиса литерала для 'func_1'
4 const obj_1 = {
5 property.1: "1",
6 func..1 : function () (return Message from func_1: 1 11 + this.property.l;}
7 };
8 // добавление второй функции func_2'
9 obj_l.property.2 = '2";
IO obj_1.func_2 = function () {return Message from func_2: " + this.property_2;};
11
12 // вызов двух функций
13 alert(obj_l.func_1 ());
14 alert(obj_1.func_2());
new
В предыдущем примере мы определили объекты, содержащие свойство со зна-
чением и другое свойство с методом. Обе части доступны через обычную точечную
нотацию Но им не хватает умной синтаксической особенности: невозможно опре-
делить их свойства напрямую при первом вызове. Что-то вроде const х = new
obj_1 ("valueOfProperty") или const mike = new Person( ‘ Mike") не срабо-
тает, потому что такой синтаксис пропускает имя свойства.
Мы изменяем и расширяем приведенный выше пример, чтобы разрешить этот
синтаксис — оператор new в сочетании с параметрами. Для этого мы определяем
функции (которые также являются объектами), которые содержат и хранят перемен-
ные, а также (внутренние) функции/методы.
1 'use strict";
2
3 function Person(name, isAlive) {
4 this.name = name;
5 this.isAlive = isAlive;
6 // (вложенная) функция для реализации некоторой функциональности
7 this.show = function () {return "The person's name is: " + this.name;};
8 }
9
10 // создание через ‘new’
11 const mike = new Perscn("Mike", true);
12 const jonn = new Person( 'John", false);
13
14 alert(mike.name + " / " + mike.show());
15 alert(john.name + ' / " + john.show());
108
Классическое ООП
Функция Person принимает параметры, как и любая другая
функция. Первая буква ее имени написана с заглавной буквы,
но это лишь соглашение, а не обязательное требование. Если функ-
ция вызывается с оператором new, на первом шаге создается но-
вый объект (https://developer.mozilla.org/en-US/docs/Web/JavaScript/
Reference/Operat ors/new).
Внутри функции можно ссылаться на новый объект с помощью ключевого слова
this, например, для хранения переданных параметров. Если, кроме того, функция
должна предоставлять некоторую функциональность в виде функций (в1гутренних),
вы определяете их и сохраняете ссылку на них в this под произвольным именем —
в примере это функция show
После определения функции вы можете использовать их с оператором new
для создания отдельных объектов (экземпляров). Такне отдельные с-бъекты хранят
переданные аргументы и предоставляют внутренне определенные функции.
Обратите внимание, что выражение new Person(. ..) отличается от обычного
вызова функции без оператора new: Ре г son (. ..). new необходим, чтобы указать,
что создание объекта должно быть выполнено до того, как тело функции сможет вы-
полниться. Без new движок JavaScript не создает объект, и использование this завер-
шится ошибкой.
Предопределенные типы данных
Многие предопределенные типы данных (Date, Array, .. .) определены описан-
ным выше способом. Поэтому вы можете использовать оператор new для их создания:
const arr = new Array ([б, 1, 2 ]). Аргументы хранятся где-то в новом создан-
ном объекте. Здесь это всего лишь один аргумент — массив, выраженный буквально.
Он разбирается, и элементы массива сохраняются. Некоторые производные свойства
вычисляются, например, длина, и предоставляется множество методов, таких как push
и pop. В целом внутренняя структура часто отличается от внешне видимой формы.
В дополнение к этому унифицированному синтаксису с new существуют некото-
рые синтаксические варианты, которые специфичны для предполагаемого типа дан-
ных. Например, для Array можно использовать const arr = [0, 1, 2].Ноэто
всего лишь сокращение для: const агг = new Аггау([О, 1, 2]).
Наследование
В данном разделе показаны различные синтаксические возможности для органи-
зации объектов в иерархии.
setPrototypeOf
Если вы определили независимые объекты, вы можете впоследствии связать
их вместе, чтобы они образовали отношение «родитель/потомок». Ключевая функ-
ция — setPrototypeOf. Как следует из названия, эта функция устанавливает один
объект в качестве прототипа другого объекта. Таким образом, свойства «родителя»,
включая функции, становятся доступными для «потомка»:
1 'use strict";
2
3 // два объекта, которые изначально независимы друг от друга
4 const parent = (property.! : "!"};
Наследование
109
5 const child = {property_2: "2'};
6
7 // alert(child property_1); // undefined в начале
8
9 // связываем их вместе
10 Object.setPrototypeOf(child, parent);
11
12 alert(child . property..!); // '1'
После успешного выполнения setPrototypeOf объект-» потом ок» «расширя-
ет» объект-«родитель». Он получает доступ ко всем свойствам объекта-«родителя»,
как показано в строке 12.
Как эго работает? Каждый объект содержит свойство с именем____proto___, даже
если оно нигде не упоминается в исходном коде. Его значение ссылается на объект,
который выступает в качестве его «родителя». Также «родитель» содержит такое
свойство___proto___, и так далее. На самом верхнем уровне значение равно null,
чтобы обозначить конец иерархии. В целом это «связанный список» объектов. Он на-
зывается цепочкой прототипов. Это сердце реализации ООП в JavaScript: «родители»
выступают в качестве прототипов для ссылающихся объектов — как для системных,
так и для пользовательских.
Движок JavaScript использует цепочку прототипов всякий раз, когда ищет какое-
либо свойство. Когда движок не находит его, он переходит на следующий уровень
и повторяет поиск.
Это применимо и в случае, когда ищется функция:
1 "use strict' ;
2
3 const parent = {
4 property-1: "1",
5 func_1: function () {return Message from func_1: " + this.property_1;}
6 };
7 const child = {
8 property_2: "2",
9 func_2: function () {return 'Message from func_2: " + this.property_2;}
10 };
11
12 // alert(child.func_1()); // невозможно в начале
13 Object.setPrototypeOf(child, parent);
14
15 alert(child.func_1()); // '1
После строки 13 метод func_1 может быть вызван объектом-«потомком», хотя
он определен объектом-«родителем».
new
Если вы заранее знаете, что эдил объект должен выступать в качестве «потомка»
другого объекта, то оператор new предлагает возможность определить зависимость
с самого начала. Уже существующий объект может быть передан в качестве параметра
в процессе создания. Движок JavaScript объединит этот существующий объект с новым
создаваемым объектом с помощью того же механизма — свойства_____proto___.
110
Классическое ООП
"use strict ;
const parent = (property_1: “1"};
// наследование через оператор new
const child = new Object(parent);
alert(child.property_l);
Object.create
Эта заранее известная иерархическая связь также может быть реализована с по-
мощью метода Object .create'
"use strict";
const parent = |property_1: "1"};
// создание через 'Object.create'
const child = Object create!parent);
alert(child.property-1);
Отличие от подходов, основанных на классах
Существуют некоторые различия между прототипным подходом JavaScript и под-
ходами, основанными на классах. Одно из этих различий, касающееся наследования,
показано здесь.
После создания иерархии прототипов и экземпляров одним из вышеуказанных
методов вы можете изменить экземпляр «родителя», чтобы одновременно изменить
все экземпляры «потомков»:
1 'use strict";
2
3 // создание небольшой иерархии
4 const parent = {property_1: "1"};
5 const child_.11 = (property,11 : 11 };
6 const child_12 = Jprooerty_12: 12"};
7
Object.setPrototypeOf(child.11, parent);
9 Object.setPrototypeOf(child_12, parent);
w
11 // показываем, что ни один из экземпляров не содержит свойство 'property_2'
12 alert(parent.property_2); Il undefined
13 alert(child_11.property.2); // undefined
14 alert(child_12.property_2); // undefined
15
16 // одно выражение добавляет property_2‘ всем трем экземплярам-
17 parent property_2 = '2";
18 alert(parent.property_2); // 2
19 alert(child_11.property_2); // 2
20 alert(child_12.property_2); // 2
Выражение в строке 17 добавляет свойство property.? (виртуально) ко всем эк-
земплярам одновременно. Всякий раз, когда property.? запрашивается последую-
щим выражением, движок JavaScript будет следовать цепочке прототипов. Сначала
Проверка иерархии объектов
111
в экземплярах «потомков» он не найдет р горе г ty_2 Но, следуя но цепочке прототи-
пов, он найдет его в экземпляре «родителя». Для экземпляров «потомков» не имеет
значения, находится ли свойство в их собственном пространстве или в пространстве
«родителя».
Отличие ог подхода, основанного на классах, заключается в том, что добавляется
не только значение новою свойства. Также расширяется структура всех экземпля-
ров: добавленное свойство вообще не существовало до строки 17.
Проверка иерархии объектов
Существуют различные способы проверки иерархии типов данных любой пере-
менной или значения.
getPrototypeOf
Метод getPrototypeOf позволяет исследовать иерархию. Он возвращает роди-
тельский объект напрямую, а не его тип данных. Если вас интересует тип дашпях
«родителя», вы должны проверить его с помощью одного из других операторов:
1 use strict";
2
3 const parent = {property.!: "1“};
4 const child.! = Object.create(parent);
5
6 // используйте console log'; это более информативно, чем 'alert'
7 console logfObject getPrototypeOf(child..1)); // {property.!: "!"}
8
9 const arr = [0, 1, 2];
10 const child_2 = Object.create(arr);
11 console.log(Object getPrototypeOf(child_2)); // 10, 1, 2]
12 console.logfObject getPrototypeOf(arr)); // I]
Или же вы можете пройтись по цепочке прототипов в гибком цикле:
1 "use strict' ;
2
3 // определяем массив с тремя элементами
4 const myArray = [0, 1, 2];
5 let theObject = myArray;
6
7 do {
8 // показываем прототип объекта
q console.log(Object.getPrototypeOf(theObject)); // Array[],
Ohject{...}, null
10
11 // переходим на следующий уровень выше
12 theObject = Object.getPrototypeOf(theObject);
13 } while (theObject);
112
Классическое ООП
instanceof
Оператор instanceof (https://developer.mozilla.org/en-US/docs/
Web/]avaScript/Reference/Operators/instanceof) проверяет, содержит
ли цепочка прототипов переменной указанный тип данных.
Он возвращает логические значение.
1 'use strict";
2
3 // определяем массив с тремя элементами
4 const myArray = [0, 1, 2];
5 alert (myArray instanceof Array); H true
6 alert (myArray instanceof Object); И true
7 alert (myArray instanceof Number) ; II false
typeof
Оператор typeof (https://developer.mozilla.org/en-US/docs/Web/
JavaScript/Reference/Operators/typeof) возвращает строку, указыва-
ющую тип данных своего операнда.
Однако он ограничен в определении только определенных ти-
пов данных или их родительских объектов. Возможные возвраща-
емые значения: undefined ', "object", "boolean", "number ',
"bigint", "string", "symbol", "function".
1 "use strict";
2
3 // определяем массив с тремя элементами
4 const myArray = [0, 1, 2],
5 let theObject = myArray;
6
7 do {
8 // показываем тип объекта
9 console.log(typeof theObject); // object, object, object
1И
11 // переходим на следующий уровень пыше
12 theObject = Object.getPr?totypeOf(theObject);
13 } while (theObject);
См. также
MDN: Прототипы (https://developer.mozilla.org/en-US/docs/Web/
JavaScript/Inheritance_and_ihe_proioiype_chain)
Классы в ООП
Популярность языков программирования, основанных на классах, вдохновляет
сообщество JavaScript на создание синтаксиса, который имитирует классовый под-
ход, поверх прототипной реализации ООП. В EcmaScript 2015 (ES6) появились соот-
ветствующие ключевые слова, такие как class или extends.
Классы являются шаблонами или «чертежами» для создания объектов. Они ин-
капсулируют данные и содержа т функции для работы с ними.
Создание
1 class Person {
2 // Тело класса всегда неявно находится в режиме "use strict'
3 constructor(name) {
4 // Данные. Объявления, такие как let х = 0 , не обязательны.
5 this.name = name;
6 }
7 // Функциональность
8 showName() {
9 return 'My name is + this.name;
10 }
11 }
12
13 const ada = new Person("Lovelace");
14 alert(ada showName());
Ключевое слово class вводит определение класса. В примере Person — это имя
класса. За ним следует тело класса, заключенное в фигурные скобки { }, строки 1-11.
Внутри тела находится специальный метод constructor. Эта функция вызывается
при создании класса. В примере она принимает один аргумент — имя человека Вну-
три const ructor этот аргумент сохраняется внутри класса с использованием ключе-
вого слова this. Класс предлагает только одну функциональность: метод showName.
Статические свойства и методы
Приведенный выше синтаксис показывает, как работать со свойствами и мето-
дами отдельных объектов (экземпляров — например, ada в примере выше). Также
можно определить свойства и методы, которые недоступны на уровне отдельных
объектов, но доступны на уровне класса — Person в примере выше. Они вводятся
с помощью ключевого слова static:
1 class Person {
2 constructor(namej {
3 // данные
4 this.name = name;
114
Классы в ООП
5 }
6
7 static className = The PERSON Class";
g static show01assName() {return "The name of this class is: " + this.
className;}
9
V showName() {
11 return "My name is: " + this.name;
12 }
13 }
14
15 const ada = new Person("Lovelace");
16 // alert(ada.showClassNaine()); // ошибка!
17 alert(Person.showClassNanieO);
Строки 7 и 8 используют ключевое слово static. Поэтому свойство и метод НЕ до-
ступны для экземпляров, только для класса в целом.
Get
Методы класса могут быть представлены как свойства. Это освобождает програм-
миста от необходимости различать доступ к методам (через скобки ()) и свойствам.
Ключевое слови get вводит эту возможность:
1 class Person {
2 constructor(name) {
3 this, name = name;
4 }
5 // геттер (getter)
6 get showTheName() {
7 return this.showName();
& }
9 // 'обычный' метод
10 showNamef) {
11 return "My name is: " + this.name;
12 }
13 }
14
15 const ada = new Person("Lovelace');
16 // БЕЗ круглых скобок ()
17 alert(ada.showTheName);
Наследование
Далее мы определяем иерархию классов Это делается с помощью ключевого
слова extends. В примере Employee является подклассом Person и имеет доступ
ко всем его свойствам и методам:
Управление доступом
115
1 class Person {
2 constructor(name) {
3 this.name = name;
4 }
5 // метод
6 showName() {
7 return "My name is: " + this.name;
8 }
9 }
10 class Employee extends Person {
11 constructor(name, company) {
12 super(name);
13 this.company = company;
14 }
15 // метод
16 showCompany() {
17 return "I, " + this.name + ", work at the company " + this.company;
18 }
19 }
29
21 const henry = new Employeef"Henry Miller", ACME Inc.");
22 alertfhenry.showCompanyf));
23 alertf henry.showNamef)); // метод родительского класса
Строка 12 вызывает конструктор родительского класса. Это необходимо, потому
что конструктор «родителя» создает this.
Управление доступом
По умолчанию свойства и методы класса доступны. Вы можете скрыть их, исполь-
зуя символ # в качестве первого символа их имени:
1 class Person {
2
3 // два скрытых свойства (иногда называемых "приватными полями')
4 #firstName;
5 #lastName;
6
7 constructor(firstName, lastName) {
8 this,#firstName = firstName;
9 this.#lastName = lastName;
10 // одно публичное свойство
11 this.name = lastName + ", " + firstName,
12 }
116
Классы в ООП
13 #showName() { // скрытый метод
14 alert("My name is ' + this.name);
15 }
16 }
17
18 const ada = new Person('Ada4, "Lovelace');
19 alert(ada.name); // ok
20 alert(add.firstName); // undefined
21 alert(ada.#firstName); // undeclared private field
22
23 alert(ada,#showName()); // undeclared private method
Полиморфизм
Если имя метода используется как в родительском классе, так и в дочернем, дви-
жок JavaScript вызывает метод из соответствующего класса:
1 class Person {
2 constructor(name) {
3 this.name = name;
4 }
5 // имя метода также используется в дочернем классе
6 showName() {
7 return "Му name is: " + this,name;
8 }
9 }
10 class Employee extends Person {
11 constructor(name, company) {
12 super(name);
13 this.company = company,
14 }
15 // то же имя метода, что и в родительском классе
16 showName() {
. return "Му name is: " + this.name + " I'm working at the company
" + this.company;
18 }
19 }
20
21 const henry = new Employee( Henry Miller’, "ACME Inc.");
22 alcrt(henry.showName()); //из Employee
23
24 const nextPerson = new Person("John");
25 alert(nextPerson.showName()); // из Person
В примере определены и используются два разных метода showName.
this
117
this
this — это не переменная и не объект; это ключевое слово. В зависимости от кон-
текста оно ссылается на разные вещи. В контексте определений классов оно ссыла-
ется на сам класс, например, this city = Nairobi ' ссылается на свойство city
текущего класса.
Когда this используется на верхнем уровне файла (другими словами, вне любой
функции или объекта), оно ссылается на глобальный объект. В функции, в строгом
режиме, this равно undefined В событии DOM оно ссылается на элемент, который
получил событие.
См. также
MDN: Классы
(hrtps://developer.
mozilla org/en-US/
docs/Web/JavaScript/
Reference/Classes)
W3Schools: OOITbJS
(www.w3schools.com/js/
js_class_intro.asp)
Модули
В ранние дни JavaScript скрипты были относительно небольшими. Во многих слу-
чаях вся функциональность находилась в одном файле JavaScript. Со временем требо
вания и решения значительно выросли. Часто используемые функции стали выно-
ситься в отдельные файлы. С ростом сложности увеличивается риск нежелательных
побочных эффектов, и необходимость модуляризации исходного кода становится
очевидной.
Без модулей
Изначальный синтаксис JavaScript (который остается действительным и по сей
день) не знает границ между исходным кодом, написанным в разных файлах или скрип-
тах. Все известно везде, независимо от организации файлов. Следующий пример пока-
зывает, что две функции известны как в HTML, так и друг другу. Одна может вызывать
другую:
<1 DOCTYPE html>
<html>
<nead>
<script>
alert("In script 1");
function function_1 () {
"use strict";
alert("In function..!") ;
function.2();
}
</script>
<script>
alert('In script 2");
function function_2 () {
"use strict";
alertC'In function.2");
}
</script>
</head>
<эосу>
^button onclick="function_1() '>Click</button?
</body>
</html>
Когда HTML-страница загружается, обе части скрипта читаются браузером; следо-
вательно. появляются два сообщения с предупреждениями. После нажатия на кнопку
вызывается функция function_1, которая, в свою очередь, вызывает function_2.
То же самое поведение происходит, если вы перенесете скрипты в отдельные файлы
и подключите их через <script src=" ./function_1 . js ’></script>
Чтобы избежать возможности нежелательных побочных эффектов от одной
функции к другой или от одного файла к другому, были разработаны различные фор-
мы модуляризации.
Модули ECMAScript (ES модули)
119
Модули ECMAScript (ES модули)
Начиная с ECMAScript 2015 (ES6) стандарт определяет синтаксис для модулей и их
поведение. Большинство браузеров поддерживают его нативно без необходимости
использования дополнительных библиотек.
В HTML синтаксис немного изменяется. Элемент <script> должен быть расши-
рен атрибутом type — <scnpt type="module">. Это объявляет файл или встро-
енный скрипт как модуль. После этою ею внугренние классы, функции, перемен-
ные и т. д. больше не видны другим встроенным скриптам, файлам или HTML.
В следующем примере нажатие на кнопку приводит к ошибке, потому что встроен-
ный скрипт с функцией function. 1 рассматривается как модуль:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <script type="module">
5 alert("In script 1“);
6 function function.1 () {
7 "use strict";
alert("In function.1");
9 }
10 </script>
11 </head?
12 <body>
13 <button onclick="function_1() >Click</outton>
14 </body>
15 </html>
По соображениям безопасности сложно создать пример с чисто встроенными
скриптами. Мы используем пример с внешним файлом. При тестировании создайте
этот файл, как показано в следующем встроенном скрипте.
• Когда HTML-страница за1ружается, она показывает сообщение с предупреж-
дением (строка 7).
• Внешний файл function_1 . js «публикует» свою функцию function_1
(строка 16). Вся остальная функциональность остается скрытой (в этом
простом примере другой функциональности нет).
• Функция function.1 импортируется во встроенный скрипт (строка 5).
• Мы добавляем обработчик события через addEventListener к кнопке
(строка 10). Обработчик события состоит из анонимной функции, которая
вызывает f unction.1 (во внешнем файле). В строке 10 обработчик события
только объявляется: в этот момент он не вызывается.
• Выражение "use strict" становится излишним, потому что модули всегда
работают в строгом режиме.
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <script type = module">
120
Модули
5 import {function.1} from "./function.), js";
6
7 alert("In script 1H);
8
9 const btn1 = document.getElementById( 'btn1 1);
10 btnl.addEventListener("click", () => function.l());
11
12 /* создайте файл 'function .1.js1 co следующим содержимым:
13 function function_1() {
14 alert("In function.l");
15 }
16 export { function_1 };
17 */
18
19 </script>
20 </head>
21 <body>
22 ^button id="btn1">Click</button>
23 </body>
24 </html>
По сути, синтаксис модулей ES6 (http://https://developer.mozilla.
org/en-US/docs/web/javascript/reference/statements/exportffsyntax) со-
стоит из двух операторов export и import.
export используется в публикующем модуле, чтобы сделать
некоторые из его классов, функций или переменных доступными
для других, import используется в вызывающем скрипте для по-
лучения доступа к этим объектам.
Модули Node.js (CommonJS)
Веб-серверы не управляются HTML-элементами. Поэтому они используют другую
технику для определения того, какие JS-скрипты должны рассматриваться как моду-
ли. а какие нет.
Популярный веб-сервер Node.js поддерживает синтаксис export/import моду-
лей ES. Но его система модулей по умолчанию отличается. Она называется CommonJS.
Чтобы указать Node.js, какой синтаксис вы используете, необходимо добавить до-
полнительную строку в файл package j son проекта:
{
"type": "module",
}
Это привадит к использованию синтаксиса модулей ES. Альтернативный спо-
соб— использование расширения .mjs вместо . js для имен фай лов. Строка "type":
" common j s" (или отсутствие определения) приводит к использованию специфично-
го дтя Node.js синтаксиса CommonJS.
См также
121
В Common JS экспорт выполняется с помощью mo dole.exports (обратите внима-
ние на дополнительную ’s'), а импорт — с помощью оператора require. Пример:
// экспорт в файле 1 logger,js'
function duLogging() { ... };
module .exports = {oc-Lcgging};
// импорт в файле 'main.js'
const dologging = require('./logger js )
См. также
MDN: Модули
(https://developer.
mozilla.org/en-US/docs/
Web/JavaScript/Guide/
Modules)
Модули Node.js
(htrps://nodejs.org/api/
modules.htm])
Генераторы
Термин генератор (generator) обозначает технику для генерации последователь-
ности «чего угодно»: чисел, строк, строк результатов запросов к базе данных, элемен-
тов массива, узлов DOM-дерева и т. д.
Он используется для предотвращения перегрузки памяти, разбивая данные на не-
большие части.
Чтобы использовать генераторы, сначала необходимо определить функцию-гене-
ратор (generator function)'11. Такие функции обозначаются символом звездочки * сра-
зу после ключевого слова function, например, function* myGenerator (
При вызове функция не выполняется мгновенно. Она запускается только непо-
средственно перед первым появлением оператора yield и возвращает «объект гене-
ратора» (Generator object). Этот объект предоставляет метод next. Последовательные
вызовы next возвращают элементы последовательности один за другим. Элементы
появляются при каждом достижении оператора yie Id внутри функции-генератора.
Примеры
• Скрипт генерирует последовательность из четырех целых чисел:
function* fourlntsf) (
let int = 0;
while (int < 4) {
yield int; 11 каждый ,next() получает текущее значение 'int
int++;
}
}
const gen = fourlntsf); // создание
alertfgen.next().value); // 0
alertfgen.next().value); // 1
alertfgen next().value); // 2
alertfgen.next().value); // 3
alertfgen,next().value); // undefined
• Каждый вызов next() возвращает не только значение, но и логическое
значение done. Таким образом, вы можете вызывать генератор в циклах:
function* fourlntsf) {
let int = 0;
while (int < 4) {
yield int;
int++;
}
}
const gen = fourlntsf); // создание
do {
const tmp = gen.nextf);
if (tmo done) {
break;
} else {
alertftmp.value); // 3. 1, 2, 3
}
} while (true)
Параметры
123
• Генерация элементов массива, запросов к базе данных или обхода дерева:
function* arrayElements() {
// для простоты используем массив; запоосы к базе данных или обход деревьев
// ясляются белее оеалистичными примерами.
const myArray = ["yellow", "green", blue"];
for (const elem of myArray) {
yield elem;
}
}
const sequence = arrayElements(); // создание
de {
const imp = sequence.next();
if (tmp.dore) {
break;
} else {
alert(tmp.value); 11 "yellow', green", blue'
}
} while (true)
• Создание бесконечной последовательности всех четных чисел:
function* evenNumbers() (
for (let 1=0, true; 1 = 1 + 2) {
yield i;
}
}
const sequence = evenNumbers(); // создание
let i = 0;
while (i < 20) {
i = sequence.next().value;
alert(i); //0,2,4,...
)
Параметры
Функция-генератор мижет принимать параметры. В этом примере параметр
pageSize определяет количество элементов массива, которые должны быть воз-
вращены:
function* pagination(arr, pageSize) {
for (let i = 0. i < arr.length; i = i + pageSize) {
yield arr.slice(i, i + pageSize);
}
}
const srr = [1, 2, 3, 4, 5, 6, 7]
const page = pagination(arr, 3);
a]ert(page.next().value); // { value [1, 2, 3], done: false }
alert(page.next().value); // { value: [4, 5, 6], done: false }
alert(page.next().value); // { value: [7], done; false }
alert(page.next().value); // { value: undefined, done: true }
Ссылки
1. MDN: Функция-генератор (Generator function) (https://developer.
niozilla.org/en-US/docs/Web/JavaScript/'Reference/Statements/function*)
Введение в Document Object Model (DOM)
HTML-страницы внутренне реа-
лизованы в виде дерева, которое со-
держит HTML-элементы (и CSS-сти-
ли) в качестве своих узлов. Это
дерево называется Document Object
Model (модель объекта документа,
DOM). JavaScript имеет полный до-
ступ к DOM. Он может перемещать-
ся по дереву, изменять дерево
и узлы, начиная от простого добав-
ления новых узлов до перестановки
нескольких областей на странице.
Небольшое замечание о тер-
минологии: из-за близости к XML
HTML использует термин элемент
(element); а из-за структуры в виде
дерева DOM использует термин
узел (node).
Узлы
При загрузке в браузер HTML-документ разбивается на дерево узлов. Например,
рассмотрим следующий HTML-фрагмент:
<div id-"exampleDiv''>This is art<br>example HTML snippet.</div>
Через DOM JavaScript видит этот фрагмент как четыре узла.
• Элемент div, от его начального тега до конечного, является одним узлом. Этот
div имеет свойство, назначенное внутри его начального тега. Это свойство
называется id и имеет значение exampleDiv.
• Три других узла в этом примере находятся внутри div. Они называются
дочерними узлами (child nodes) div, потому что div содержит их.
Соответственно, div является их родительским узлом (parent node).
• Первый дочерний элемент div — это текстовый узел со значением “This is
ап’’. Текстовые узлы содержат только текст; они никогда не содержат тегов,
поэтому дерево на этом заканчивается.
• Тег b г — это еще один узел.
• Остальной текст — это еще один текстовый узел.
Поскольку текстовые узлы и тег b г имеют одного и того же «родителя», они назы-
ваются узлами-соседями (sibling nodes).
Доступ к узлам
Вы можете получить доступ к узлам дерева DOM с помощью различных методов.
Один из них — getElementByld.
Доступ к содержимому
125
<iDOCTYPE html>
<html>
<head>
<script>
function go() {
"use strict";
const p = document.getElementBy!d("p2") ;
alert(p.innerHTML);
}
</script>
</head>
<oody id="body“>
^p id-"p1 ' style= background aqua >one</p>
< p id="p2" style= background green'>two</p>
< p id="p3" style='background. red'>tnree</p>
<button onciick-''go()">Show the second paragrapn</button>
</body>
</html>
При нажатии на кнопку вызывается функция до. Она получает доступ к элементу
cid р2 ' и показывает его содержимое.
Доступ к содержимому
Если вы хотите получить доступ к содержимому узла вы можете использовать
различные свойства разных классов:
Node.textC untent
(https://developer.
mozilla.org'en-US/
docs/Web/API/Node/
textcontent)
HTMLElement.
innerText
(https://developer.
mozilla.org/en-
US/docs/Web/API/
HTMLElement/
innerText)
Elemen t.innerHTML
(https://developer.
moziHa.org/en-
US/docs/Web/
APl/Element/
innerHTML)
Они не равнознач-
ны; пожалуйста,
учитывайте раз-
личия
(https://developer.
mozilla.org/en-US/
docs/Web/API/Node/
textContent)
Чтобы наши примеры были понятными и простыми, мы используем Element.
innerHTML везде, где это возможно, так как это свойство очень близко к исходному
коду HTML.
const exampleContent = document.getElemeniById("example").innerHTML,
Изменение содержимого
После доступа к узлу вы можете изменить его содержимое, присвоив новое зна-
чение его свойству:
126
Введение в Document Object ModelJDOM)
<!DOCTYPE html>
<html>
<head>
<script>
function go() {
''use strict";
const p = document.getElementt!yid( p2");
p.innerHTML = "Another text";
}
</script>
</head>
«body id= body'>
< p id="p1" style=''background: aqua'>one«/p>
«p id='p2" style="background: green">two«/p>
< p id-"p3" style=''backgrouncr red"?three«/p>
«button onclick="go() >Change the second paragraph*/button>
</body>
</html>
При нажатии на кнопку вызывается функция до. Она снова получает доступ к эле -
менту с id ' р2' и изменяет его содержимое.
Изменение структуры дерева
JavaScript может изменять структуру дерева DOM:
«'DOCTYPE htffll>
<html>
<head>
*scnpt>
function go() {
"use strict";
// читаем узел 'body'
const b = document.gctElcmeniByldJ1 body');
// читаем второй узел ' p'
const p = document getElementById(1p2");
// перемещаем его в конец body'
b . appendChild(р);
}
</script>
</head>
«body id= body>
< p id="p1" style-"background : aqua'>one«/p>
< p id="p2" style-"background. green ">two«/p>
< p id="p3“ style=''background; red‘>three«/p>
«button jnclick="go()">Move the second paragraph«/button>
</oody>
</html>
При нажатии на кнопку вызывается функция дс. Она получает доступ к элемен-
там body и р2, а затем перемещает элемент р в конец body.
См. также
MDN: DOM (https://developer.mozilla.org/en-US/docs/Web/API/
Document .Object .Model)
Поиск элементов
Для работы с узлами дерева DOM (Document Object Model) необ-
ходимо либо напрямую находить их, либо перемещаться по ним,
нашитая с определенной точки. Интерфейс Document (https://
developer.mozilla.org/en-US/docs/Web/APl/Document) служит точкой
входа в содержимое веб-страницы.
Он предоставляет богатый набор свойств и методов для доступа к определенным
узлам. Методы возвращают либо один узел, либо массив узлов.
Мы используем следующую HTML-страницу для демонстрации наиболее важных
методов:
<!DOCTYPE html>
<html>
<head>
<script>
function show() {
"use strict";
// ...
}
</script>
<style>
.head_2 {
display flex;
justify-content: center;
}
.text {
padding-left' 1em;
font-size: 1.4eni;
}
.button {
height:1,4em;
width: 4em;
margin-top. 1em;
font-size: 1.2em;
background-color: Aqua;
}
</style>
</head>
<body>
<h1>An HTML header</h1>
<h2 class='head.2">An HTML sub-header</h2>
<aiv id="div_1">
< p id=”p1" class="text">Paragraph 1</p>
< p id="p2" class="text">Paragraph 2</p>
< p id="p3" class="text">Paragraph 3</p>
</div>
<div id="div_2“>
< h2>Anoiher HTML sub-header</h2>
<div id="div_3">
128
Поиск элементов
<p>Another paragraph 1</р>
<p>Another paragraph 2</p>
<p>Anocher paragraph 3</p>
</div>
</div>
«button class="button" onclick=,,shoft,() ">Go</button>
</body>
</hTml>
Нажатие на кнопку вызывает функцию show. Примеры должны быть включены
в эту функцию.
Использование ID
Простой, быстрый и точный способ найти отдельный элемент — это пометить его
свойством id в HTML, например, <р id=" р2" >, и использовать этот id в качестве па-
раметра для метода getElementByld(). Следующий фрагмент кода найдет элемент
и отобразит его содержимое:
function show() {
“use strict";
const elem = document getElementBy!d(' p2 );
aiert(elem.innerHTML);
}
Метод getElementByld возвращает один элемент (первый с этим id, если id
не уникален). Это также верно, если элемент является не текстовым узлом, а узлом
с дочерними элементами. Возвращаемое значение — это один элемент со всеми его
дочерними элементами:
function show() {
"use strict";
const elem = document.getElementByld("div_3“);
a3ert(elem.innerHTML);
}
// ожидаемый вывод
// <p>Another paragraph 1</p>
// <p>Another paragraph 2</p>
// <p>Anocher paragrapn 3</p>
Использование имени тега
Другой способ найти элементы на HTML-странице — это метод
getElementsByTagName. Он принимает имя тега, например, 'hl', 'div' или ' р‘,
и возвращает все такие элементы в виде массива.
Здесь мы используем метод для получения массива всех элементов ' div'
function show() {
"use strict";
// если вы хотите искать во всем документе, вы должны указать 'document'
let elemArray = document.getElementsByTagName("div");
// цикл по всем элементам массива
for (let i = 0; i < elemArray.length; i++) {
alert(elemArray[i].innerHTML);
}
Использование имени класса
129
alert("Part 2");
// если вы хотите искать только в поддереве, ы должны сначала найти
// корень этого поддерева
const elem = document.getElementById("div_2");
elemArray = elem.gelElementsByTayName(‘'div “) ;
for (let i = 0; i < elemArray.length; 1++) (
alert(elemArray[i] innerHTML);
}
}
Использование имени класса
Элементы также можно найти по связанному с ними CSS-классу. Селекторы клас-
сов могут иметь сложный синтаксис. Здесь мы используем только простую форму
имен классов.
Пример извлекает все элементы, которые используют CSS-класс text — это дела-
ют три параграфа первого div. Обратите внимание, что другие параграфы не извле-
каются:
function show() {
"use strict1 ;
let elemArray = document.getElementsByClassName("text');
// цикл по всем элементам массива
for (let i = 0; i < elemArray.length; i++) {
alert(elemArray[i].innerHTML);
}
}
Использование селектора запросов
Показанные методы поиска используют специализированную семантику для на-
хождения элементов. Но существует также общий метод, который объединяет все
это — и даже больше.
Селекторы запросов (https://developer.mozilla org/en-US/docs/
Web/API/Document_object_model/Locating_DOM_elements_using_
selectors) используют сложный синтаксис, состоящий из ID эле-
ментов HTML, имен элементов HTML, атрибутов HTML, CSS-клас-
сов, позиций и многого другого.
Они находят либо один элемент, либо список элементов. Чтобы
получить первый элемент, удовлетворяющий селектору, исполь-
зуйте метод querySelector. Если вы хотите получить все соот-
ветствующие элементы, используйте querySelectorAll:
function show() {
"use strict";
// '#' ищет no ID. ищет по CSS-классу
let elemArray = document.querySelectorAll("hl, #p2, .head_2");
// цикл no всем элементам массива
for (let 1=3, i < elemArray.length; i++) {
alert(elemArray[i]. innerHTNL);
}
}
130
Поиск элементов
Навигация по дереву DOM
Вы можете перемещаться по дереву D0M в направлении «от корня к листьям».
Это делается путем нахождения элемента и использования этого узла в качестве но-
вого корня для последующих шагов навигации:
function show() {
"use strict";
// начинаем c div_2‘
const elem_1 = document.getElementById( div_2");
// используем этот элемент как новый корень для дальнейших выборок
const elemArray = elem_1.getElementsByTagName("h2‘ );
for (let 1 = 0; i < elemArray.length; i++) {
alert(elemArray[i].innerHTML);
}
// выбирается только дочерний h?1! Первый 'h21 игнорируется
}
См. также
Методы D0M (https://developer.mozilla.org/en-US/docs/Web/APl/
Documentflinstance. methods)
Изменение элементов
Далее мы покажем, как изменить две разные части HTML-элемента. а именно
DOM-узла:
• Его содержимое (оно может быть только одно или отсутствовать)
• Любой из его атрибутов (их может быть много)
Обратите внимание на различие между содержимым и атрибутами:
<!-- в общем случае: -->
<element_name attribute.name="attribute,value >содержимое элемента</е1етегп_пате>
<!-- конкретный пример, ‘href - это атрибут. 'Visit IANa...' - содержимое. —>
<а href='https://www.example.com">Visit IANA s example domain.</a>
Пример страницы
Мы используем следующий пример HTML-страницы для демонстрации возмож-
ностей:
<'DOCTYPE html>
<html>
<head>
<script>
function show() {
"use strict";
// ...
}
</scripr>
</head>
<body id® body" style="margjn:2em">
<p id="p1“ style="background aqua >A blue paragraph</p>
<svg id="svgSrc" width="100' height="100' viewBox="0 0 1й0 1Э0">
<circle cx="50" cy="50" r=*25" fill=‘green'7>
</svg>
<p />
<a id="refToSomewhere ’ href=' https://www.example.com">Visit lANA's example domain </
a>
<p />
<button id="buttonShow" onclick="show()">Start</button>
</body>
</html>
Нажатие на кнопку вызывает функцию show. Примеры должны быть включены
в нее.
Изменение содержимого
Мы используем пример с параграфом р Чтобы изменить его содержимое (текст),
просто присвойте новое значение его свойству innerHTML:
132
Изменение элементов
function show() {
"use strict";
// получаем элемент с идентификатором ' р1
const elem = document.getElementById( р1 ');
11 изменяем содержимое элемента на 'New text in the paragraph.
elem.innerHTML = "New text in the paragraph.";
}
Или, чтобы сделать то же самое с другим HTML-элементом, мы изменяем SVG-rpa-
фику:
function show() {
"use strict";
const elem = document.getFlementBy!d("svgSrc");
elem.innerHTML = "<rect width='80 height='4c fill='blue /> ;
}
Поскольку новый текст является HTML-кодом, вы можете «злоупотреблять» этим
подходом для добавления дочерних узлов:
function show() {
"use strict";
const elem = document.getElementByldf p! );
elem.innerHTML = "New text in the paragraph <p>next P</p><p>and even one more P</
p>";
}
Скрипт вставляет два дополнительных параграфа, но не после первого. Они нахо-
дятся внутри первого:
<р id-"p1">New text in the paragraph
<p>next F</p>
<p>and even one more P</p>
</p>
Изменение атрибута
В общем случае синтаксис для изменения атрибутов выглядит следующим об-
разом:
element_name.attribute_name = "new value";
// или:
element_name.setAttribute("attribute_name", "new value');
HTML-элемент а имеет атрибут h ref : <a id="refToSomewhere" h ref= "https://
www. example, com >... </a>. Этот атрибут href можно изменить:
function show() {
"use strict";
const elem = document. getElementByldfrefToSomewhere") ;
elem,href = "https://en.wikibooks org";
elem.innerHTML = "Link changed";
}
Сначала находится элемент. Затем функция присваивает новое значение его
атрибуту href (и innerHTML).
См также
133
Следующий пример изменяет атрибут src элемента img и атрибут value элемен-
та button;
И HTML
<img id='imgCne" src= "myPicture.jpg >
<input id="buttonOne ' value="I’m a button1">
// JavaScript
document getElementById("lmgOne ).src = 'othorPicture.jpg";
const b = document getElemenrByTdt"buttonOne");
b.value = "I'm a changed button";
setAttribute()
Изменение атрибутов также можно выполнить с помощью функции
setAttribute:
function show() {
"use strict";
const elem: = document . getElementBy!d("refloSomewhere');
elem.setAttribute("href", "https:I/en.wikibooks.org");
elem.innerHTML = "Link changed ;
}
См. также
MDN: setAnribute (hups://developer.mozilla.org/en-US/docs,'Web/
API/Eleinent/setAttnbute)
Добавление элементов
Интерфейс Document (htrps://devel(jper.mozilla.org/en-DS/docs/
Web/'API/Document) DOM предоставляет (среди прочего) функции,
которые создают новые элементы, включая их атрибуты и содер-
жимое, а также объединяют их вместе или в существующий DOM.
• с reat eElement () создает элемент,
• createAttribute() создает атрибут, который можно присвоить новому
или уже существующему элементу.
• setAttribute() создает атрибут и связывает его с существую]цим элементом.
• appendChild () интегрирует элемент в другой.
Создание элементов
// Создание элемента <р>
const р = document createElement("p");
// Его содержимое
p.innerHTMl = 'The new paragraph.
Теперь элемент и его содержимое созданы. Но пока они не являются частью DOM.
Они существуют только в памяти JavaScript-движка.
Чтобы интегрировать их на страницу, мы извлекаем элемент body или любой
другой элемент существующей страницы и добавляем новый элемент как послед-
ний дочерний элемент:
const body = document,getElementRyTd("pody");
body.appendChild(p);
В целом HTML плюс JavaScript выглядят так:
<!DOCTYPE html>
<html>
<head>
<script>
function show() {
"use strict";
Il создаем элемент ^p?
const p = document.createElement("p");
11 создаем его содержимое
p innerHTML = The new paragraph.";
// добавляем его в тело документа
const body = document.getElementBy!d( body");
body.appendChild(p);
}
</script>
</head>
<body id="body' style="margin.2em >
<button id="buttonShow" onclick=' snow() ">Start</button>
</body>
</html>
Создание атрибутов
135
Исходная страница не содержит нара1рафа. Но после нажатия на кнопку пара-
граф интегрируется на страницу и становится видимым. Кстати, вы можете нажать
на кнопку несколько раз. Что произойдет?
Создание атрибутов
Атрибуты создаются с помощью функций createAtt ribute() или setAttribute().
Первая из них действует аналогично функции createElement(), описанной выше.
Она создает новый атрибут только в памяти без связи с другими элементами. Поскольку
set Att г i bute () интегрирует новый атрибут непосредственно в элемент, мы использу-
ем этот вариан т.
Пример использует элемент а с его атрибутом href:
// Создание элемента <а>
const anchor = document.createElement( a' );
// Его содержимое
anchor.innerHTML = "The IANA example domain.";
// Eiо атрибут href1
anchor.setAttribute("href", "https.//wiAw.example.com");
Теперь элемент, один атрибут и содержимое элемента созданы, Снова интегриру-
ем их на страницу, как мы делали выше.
В целом HTML плюс JavaScripl выглядят так:
<’DOCTYPE html>
<html>
«heads
<script>
function show() {
'use strict";
// создаем элемент «as
const anchor = document.createElement("a");
// создаем его содержимое
anchor.inner HTML = "The IANA example domain.' ;
// создаем атрибут href
anchor.setAttribute("href", 'https://www.exampie.com");
// альтернативный вариант: anchor.href = "https://www.example.com";
// добавляем элемент вместе с атрибутом в тело документа
const body = document.getElementById( body");
body.appendChild(anchor);
/* теперь тело документа выглядит так-
«button id='buttonSliow' onclick="show()’>Start«/button>
<a href="https://www.example.coin">The IANA example domain,</a>
*/
}
«/scripts
«/heads
«body id-"body style=''margin:2em's
«button id="buttonShow" onclick="show()'>Start«/button>
«/body>
«/html»
Исходная страница не содержит ссылки. Но после нажатия на кнопку ссылка
на примерную страницу 1ANA интегрируется на страницу и становится доступной.
136
Добавление элементов
Альтернативный синтаксис
На одной из предыдущих страниц было объяснено, как изменять атрибуты с ис-
пользованием другого синтаксиса.
element_name.attribute_name = "new value1';
Просто используйте элемент плюс имя ею атрибута и присвойте ему значение
атрибута. Если вы измените предыдущий пример на этот синтаксис, вы получите
то же поведение добавления ссылки:
anchor.href = 'https.//www.example.com";
/I вместо
11 anchor serAttribute("href , "https://www.example.com );
Соединение частей
Показанные функции со гдают элементы и атрибуты. Такие новые объекты могут
быть объединены вместе для создания более крупных частей — конечно, вложен-
ным образом. И они могут быть объединены с уже существующей HTML-страницей,
соответственно, деревом D0M:
const div = document.getElementflyId('div_1 );
ccnst anchor = document.createElement( a");
div.appendChiId(anchor);
«Неправильное» использование innerHTML
Содержимое элемента может быть изменено путем присвоения нового значения
его свойству innerHTML. Если это новое значение содержит строковое представле-
ние HTML-фрагмента, присвоение создает дочерние узлы внутри элемента. Это воз-
можно, но не является предназначенным способом использования innerHTML:
const elem = document.getElementByld("р1");
elem.innerHTML = New text in the paragraph.<p>next P</p><p>and even one more P</p>";
... приводит к ..
<p id="p1">New text in the paragraph
<p>next P</p>
<p>and even one more P</p>
</p>
JavaScript-фрагмент вставляет еще два параграфа, но не после первою. Они суще-
ствуют внутри первого.
write()
Устаревшая функция document .write() могла вставлять но-
вые элементы в HTML-страницу. Ее использование настоятельно
не рекомендуется (https://developer.mozilla.org/en-US/docs/Web/API/
Document/write) в настоящее время.
См также
137
См. также
MDN; Create Element
(https ://d eve! oper.mozilla.
org/en-US/docs/Web'API/
Document/createElement)
MDN. Set Attribute
(htips://developer.mozilla.
org/en-US/docs/Web/API/
El ement/set Attri bute)
MDN: Append Child
(https://develo per.mozilla.
org/en-US/docsTWeb/APl/
Node/appendChild)
Удаление элементов
HTML-страницы и объекты DOM (Document Object Model) имеют иерархическую
структуру. Каждый элемент и атрибут принадлежит ровно одному родительскому
элементу. Чтобы удалить элемент или атрибут, сначала необходимо найти родитель-
ский элемент. Операция удаления выполняется для этого объекта.
Удаление элементов
Элементы удаляются с помощью функции removeChild. Чтобы удалить элемент
<р> из элемента <div> в следующем примере:
<div id='-parent"*
<р id="child>l m a child!<Ур>
</div>
JavaScript-код будет выглядеть так:
// получить элементы
const parent = document.getElementBy!d('parent );
const child = document .getElemen(.ById(1 child');
// удалить дочерний элемент
parent.removeChild(child);
Оставшаяся структура HTML будет следующей:
<div id=-"parent‘></div>
Дочерние элементы дочерних элементов
Если элемент удаляется, все его дочерние элементы также удаляются. Таким об-
разом, можно удалить большие части DOM одной командой, если они имеют общий
корень. Например, удаление всего списка:
<div id="div_1>
<ul id=’listOfNames"*
<li*Albert</li>
<li*Berty</li>
<li*Charles</li>
</ul>
</div*
JavaScript-фрагмент удаляет элемент <ul>, а также все элементы <li>:
const parent = document.getElementBy!d(“div_1");
const child = document,getElementById("listOfNames");
parent.remcveChild(child);
Свойство parentNode
Чтобы удалить элемент, необходимо знать его родительский элемент. Если вы мо-
жете найти только дочерний элемент, но по какой-то причтите не можете найти ро-
дительский, свойство parentNode дочернего элемента укажет путь.
Удаление атрибутов
139
// получаем дочерний элемент
const child - document .getElementBy Id (. child );
// находим родительский элемент
const parent = child.parentNode; Il без скобок ()
// удаляем дочерний элемент из документа
parent.removeChild(chilo);
Удаление атрибутов
Атрибуты удаляются с помощью функции removeAttribute. Чтобы удалить
атрибут href из элемента <а> в следующем примере:
<а id="anchor" href='https://en.wikiDooks.org >Wikibuok</a>
JavaScript-код будет выглядеть так:
// получаем элемент
const anchor = document.getElementBy!d("anchor');
// удаляем атрибут
anchor.removeAttribute("href”);
Сам элемент, включая текст ссылки, останется, но по ней больше нельзя будет пе-
рейти,
См. также
MDN: Remove Child
(https://deveioper.
mozilla.org/en-US/
docs/Web/API/Node/
removechild)
MDN. Remove Attribute
(https ://developpr.
mozilla.org/en-US/
docs/W eb/APl/Element/
removeAttribute)
Реструктуризация DOM
Помимо добавления и удаления узлов распространенной операцией над деревья-
ми является перестановка узлов или поддеревьев. В некоторых предыдущих приме-
рах мы видели, что appendChild добавляет узел в качестве последнего дочернего
элемента родительского узла. Та же операция возможна для существующего узла. Та-
ким образом, это подходящая функция для выполнения перестановок.
Пример страницы
Мы используем следующий пример HTML-страницы для демонстрации возмож-
ностей:
<! DOCTYPE hitml>
<ntml>
<head>
<script>
function show() {
"use strict';
// ...
}
</script>
</head>
<ooay id="body" style="niargin:2em >
<h1>The magic manipulator</h1>
<button id="buttonShow' onclick="show()" style='margin:1em нет 1em 0em >Start</
button*
<div id="div_1">Our sweet products
<ul id= ul_1 >
<li id-"li_11">Ice creme</li>
<li id="li_12"*Chocolate</li>
<li id=*li_13“>Coffee</li>
</ul>
</div>
<div id="div_2">Additional offers
<ul id="ul_2'>
<11 id="ll_2l">Creme</li>
<li id="li_22">Sugar</li>
<li id="li_23">Cakes</li>
</ul>
</div>
</budy*
</html>
Перемещение элемента в конец списка соседей
(дочерних элементов одного уровня)
Мы идентифицируем два элемента и перемещаем их в конец другого узла. Этот
,другой узел не обязательно является старым «родителем». Но после перемощения
он становится новым «родителем».
Перемещение элемента перед соседом (дочерним элементом одного уровня) 141
function show() {
"use strict",
// выбираем первый <ul> как нового 'родителя'
const ul_1 = document getElementBy!d("ul_1");
// выбираем два элемента <li>, которые нужно переместить
const li_11 = document.getElementfiyId("li_ll");
const 11.23 = document.getElemcntById("li_23 "); // Элемент 'cakes'
// перемещаем два дочерних элемента
u 1_ 1.appendChi]d(li_11);
ul_1.appendChi]d(li_23);
}
Как видите, элемент ' Ice creme перемещается в конец (временно) своей груп-
пы продуктов. После этою элемент ' cakes', который был дочерним элементом вто-
рой группы продуктов, перемещается в конец первой группы продуктов.
Перемещение элемента перед соседом
(дочерним элементом одного уровня)
Вы можете переместить элемент в любое место внутри группы соседей (дочерних
элементов одного уровня). Сначала необходимо найти родительский элемент. Затем
найдите дочерний элемент, который должен стать новым преемником перемещае-
мого элемента. Когда оба узла известны, функция insertBefore вставляет элемент
на эту позицию.
В качестве примера мы перемещаем элемент ' Cakes' на первое место в первой
группе нродукгив:
function show() {
"use strict";
// выбираем первый элемент <ul>; он будет родителем"
const ul_1 = document.getElementById(''ul-1");
// выбираем первый элемент <li>; он нужен для позиционирования
const li_11 = document.gecElementById("li_11");
11 выбираем элемент <li> c 'Cakes
const li_23 = document.getElementById("li_23");
// перемещаем ‘Cakes на первое место в первой группе продуктов
ul.1.insertBefore(li_23, li_11);
}
Здесь элемент Cakes' становится первым элементом первой группы продуктов.
С помощью тех же команд вы можете переместить его в любое место в последова-
тельности соседей (siblings). Просто найдите соседа, который должен стать его новым
преемником вместо ' 11_11'.
Атрибуты
Последовательность атрибутов внутри элемента не имеет значения. Следователь-
но, нет необходимости и нет функции для их перестановки. Когда DOM сериализует-
ся, программы могут делать это по-разному (оригинальная последовательность, ал-
фавитный порядок и т. д.).
142
Реструктуризация DOM
См. также
MDN: Append Child
(https://developer.
mozilla.org/en-US/
docs/W eb/A PI/Node/
appendChild)
MDN: Insert Before
(https://developer.
mozilla.org/en-US/
docs/Web/API/Node/
insertBefore)
Изменение стилей элементов
Как вы видели в предыдущих главах, атрибуты элемента могут быть изменены
с помощью JavaScript. Два атрибута — class и style — влияют па визуальное пред-
ставление элемента. Они содержат CSS-код:
<!DOCTYPE html>
<html>
<head>
<script>
function toggleO {
"use strict";
// ...
}
</script>
<style>
divClassGreen {
hackground-color: green;
padding- 2em;
margin: lem;
}
.divClassRed {
background-color: red,
padding: 2em;
margin: 1em;
}
</style>
</head>
<body id="body">
<div id='div_T class="divClassGreen' >A DIV element</div>
*div id="div_2 1 style= background-color. blue, padding. 2em; margin: 1em>Another
DIV element</div>
«button id=' buttonloggle onclick= toggleO" style="margin 1em 0em lem гет >Start</
button>
</body>
</html>
Атрибут class идентифицирует CSS-класс, который создан в элементе <style>
HTML. Атрибут style определяет CSS-правила встроенно (локально).
Для их изменения обращайтесь с ними как с любыми другими атрибутами.
Для них нет специальных правил или исключений.
Пример
Мы используем вышеуказанный HTML-файл; изменена только JavaScript функ-
ция. Когда кнопка нажата, функция присваивает CSS-класс divClassRed элементу
div_1 и изменяет встроенный атрибут style элемента div_2 на другое значение:
function toggle() {
"use strict";
144
Изменение стилей элементов
// нахсдим элементы, которые нужно изменить
const div_1 = document.getElementByldJ div_1");
const div_2 = document.getElemenlByld(' div_2");
Il изменяем атрибут class'
div_1,setAttribute("classdivClassRed 1);
!/ встроенное (inline) изменение
div_2.setAttribute("style", "background-color: silver; padding 4em; margin:
2em );
Il альтернативный вариант: div_2.style = "background-color: silver; padding: 4em;
margin: 2em";
}
Атрибут style хранит CSS-свойства, такие как color или padding, в своих соб-
ственных свойствах. Это соотносится с общими правилами объектов JavaScript. Поэто-
му следующий синтаксис эквивалентен предыдущему вызову div_2. setAttribute.
div_2.style backgroundColor = "silver";
div_2.style padding = 4em";
div.2.style.margin = "2em";
Свойства style
В CSS некоторые свойства определены с дефисом в их имени, например,
background-color или font-size. Когда вы используете их в JavaScript в син-
таксисе свойства style, имена немного изменяются. Символ после дефиса должен
быть записан в верхнем регистре, а сам дефис исчезает: style.backgroundColor
или style. f ontSize. Эти называется camel-case:
div_1.style.fontSize = "2епГ ; // размер шрифта как свойство 'style
/*
Следующая строка вызовет синтаксическую ошибку, потому что дефис
будет интерпретирован как операция вычитания.
div_1.style.font-size = "2em";
*/
Все остальные места, где такие имена встречаются в CSS, не изменяются. В частно-
сти, показанный синтаксис с дефисами внутри HTML-элемента <style*, а также ис-
пользование в форме встроенного определения, остаются неизменными.
См. также
MDN: Основы CSS (https://developer.mozilla.org;en-lJS/'docs/Learn/
Getnng_started_with_the_web/CSS_basics)
Обработка событий DOM
Приложения с пользовательским интерфейсом (а также дру-
гие типы приложений) в основном управляются событиями.
Здесь мы сосредоточимся на событиях DOM (https://w3c.github.io/
uievents/).
Они возникают (или «срабатывают») в результате определенных действий или си-
туаций в браузере или нативном приложении, например, когда пользователь клика-
ет мышью, нажимает клавишу на клавиатуре или работает с сенсорным экраном; ви-
зуальный объект «перетаскивается» (drag & drop), «копируется и вставляется» (сору &
paste) или изменяет размер; HTML-страница загружается или должна быть выгруже-
на; браузер или визуальный объект получает или теряет фокус на нем; и многое дру-
гое. Также возможно, что приложение создает события программно (dispatch).
Событие связано с объектом, из которого оно произошло, и с JavaScnpt-выражени-
ем; то есть в большинстве случаев это вызов функции, которая обозначена как обра-
ботчик события (event handler). JavaScript-часть выполняется после возникновения
события. Типичные действия включают взаимодействие с сервером, проверку вве-
денных пользователем данных юти изменение D0M либо графики.
Создание и вызов событий
Встроенные в HTML
Короткий пример показывает, как события определяются на HTML-странице,
срабатывают и выполняются. Эта версия синтаксиса обозначается как встроенный
JavaScript (inline JavaScript):
<!DOCTYPE html>
«html?
<head>
«scripts
function handleEvent(evt) {
''use strict";
alert("Perform sone actions via a JavaScript function.");
}
</script>
«/heads
«body id="body" style="margin:2em">
<!-- встроенные (inline) инструкции; необычный подход -->
«button onclick-‘const msg= Direct invocation of snail actions.' ; alert(msg);"sFirst
button«/button>
«!-- вызов функции (обработчик события) -->
«button onclick="handleEvent(event)'>Second button«/button>
</body>
</ntml>
Когда пользователь кликает по одной из кнопок, браузер читает атрибут onclick
кнопки, создает объект JavaScript, который содержит все свойства события, и выпол-
няет ]ауа5сг!р(-выражение(я). В большинстве случаев JavaScript-часть представля-
146
Обработка событий DOM
ет собой вызов функции. Эта функция обозначается как обработчик события (event
handler). Она получает объект JavaScript в качестве своего первого параметра. Только
в очень простых случаях весь JavaScript-скрипт встроен.
Конечно, вызываемая функция должна где-то существовать. Некоторые стандарт-
ные функции, такие как alert (), предопределены и предоставляются браузером.
Ваши собственные функции существуют внутри HTML-тега <scnpt>, или тег ссы-
лается на файл либо URL, где они находятся.
Подсказка: встраивание определений событий непосред-
ственно в HTML называется встроенным JavaScript (inline Jt/S
JavaScript). Это самый ранний метод встраивания обработчиков
событий, но он может сделать исходный код трудным для чте-
ния в нетривиальных приложениях. Поэтому его можно считать
менее предпочтительным методом (https://developer.mozilla.org/ $ г
en-US/docs/Learn/JavaScript/Bui]ding_blocks/Events#inline_event_
handlers_%E2%80%94_dont_use_these) по сравнению с другими не-
навязчивыми техниками.
Использование встроенного JavaScript можно считать аналогичным использова-
нию встроенного CSS, где HTML стилизуется путем добавления CSS в атрибуты style.
Тем не менее данная книга часто будет рассматривать встроенный JavaScript в де-
монстрационных страницах, потому что его синтаксис короткий, а концепция про-
ста для понимания.
Программно в JavaScript
JavaScript «знает» два способа встроить обработчик события для HTML-элемента.
Во-первых, функция обработчика события может быть напрямую назначена свой-
ствам элемента onxxx (onclick, onkeydown, onload, onfocus, . . .). Их имена на-
чинаются с ' on' и заканчиваются значением типа события. Во-вторых, функция
addEventListener регистрирует тип события и обработчик события:
1 <IDOCTYPE html>
2 <html>
3 <head>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script> function register() { 'use st riot' ; const pl = document.getElement3y!d('p1"); // делаем так ... pl.onclick = showMessage; // без скобок () // ... или так (предпочтительно) //pl.addEventListener('click', showMessage); alert("The event handler is assigned to the paragraph.’); } function showMessage(evt) { "use strict'; // параметр 'evt содержит много информации о событии, // например позицию, откуда оно произошло
Типы событий
147
19 alert("Событие клика на абзац. Позиция: " +
20 evt.clientX + " / " + evt.clientY + ". Тип события: ' + evt.type);
21 }
22 </script>
23 </head>
24
25 <body>
26 <Ь1>Регистрация событиж/Ы>
27 <p id="p1" style= margin :2ein; background-color:aqua">
28 Небольшой абзац. Сначала без обработчика события, затем с ним.
29 </р>
30 <button onclick="register()" id= button_1">KHonKa</button>
31 </body>
32 </html>
Обработчик события onclick ' register' кнопки 'button_1' регистрируется
с использованием вышеупомянутого встроенного JavaScript-синтаксиса. Когда страни-
ца загружается, известен только этот обработчик события. Клики по параграфу ' р1 '
не вызывают никаких действий, потому что у него пока нет никакого обработчика со-
бытия. Но когда кнопка нажимается, обработчик кнопки ' button .1' регистрирует
второй обработчик события — функцию ' showMessage' Теперь, после клика по па-
раграфу, появляется предупреждение «А click-event to the paragraph ..».
Регистрация выполняется в строке 10: р1 .onclick = showMessage. Заметное
отличие от встроенного JavaScript заключается в том, что здесь нет скобок. Встроен-
ный JavaScript вызывает функцию showMessage, и поэтому ему нужно использовать
скобки. Функция register НЕ вызывает showMessage Она использует только ее
имя для процесса регистрации.
Альтернативой назначению функции свойству 'onclick' параграфа является
использование функции addEventListener. Она действует на элемент ' р1' и при-
нимает два параметра. Первый — это тип события (click, keydown,...). Такие типы
событий коррелируют с именами опххх, за исключением того, что в них отсутствуют
первые два символа ' on'. Второй параметр — это имя функции, которая действует
как обработчик события.
Вы можете протестировать пример, закомментировав либо строку 10. либо стро-
ку 12. Строка 12 с функцией addEventListener является более предпочтительной
версией.
Типы событий
Существуют различные типы событий в зависимости от типа
элемента, который их инициирует. Полный список типов собы-
тий невероятно обширен (MDN) (https://developer.mozilla.org/en-US/
docs/Web/Events#event Jndcx)
(W3schools) (https://www.w3schools.com/jsref/dom_obj_event.asp)
ЕЖЕ
’jrlneW:’.*
148
Обработка событий DOM
Мы покажем некоторые важные тины и примеры
Название Описание
blur Элемент ввода теряет фокус
change Элемент изменен
click Элемент был кликнут
dblclick Элемент был кликнут дважды
error Произошла ошибка при загрузке элемента
focus Элемент ввода получил фокус
keydown Клавиша была нажата, когда элемент имел фокус
keyup Клавиша была отпущена, когда элемент имел фокус
load Элемент был загружен
mouseenter Указатель мыши был перемещен внутрь элемента
mousemove Указатель мыши перемещается внутри элемента
mousedown Кнопка мыши была нажата на элементе
mouseup Кнопка мыши была отпущена на элементе
mouseleave Указатель мыши был перемещен за пределы элемента
reset Кнопка сброса формы была нажата
resize Окно или кадр (фрейм) были изменены в размере
select Был выбран некоторый текст внутри элемента
submit Форма отправляется
unload Контент выгружается (например, окно закрывается)
Следующий пример демонстрирует различные типы событий:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <script>
5 function regisferAllEvents() {
6 "use strict";
Типы событий
149
7 // регистрация различных типог событий
8 document.getElementByld("р1").addEventListener("click", handleAHEvents);
_ document.getElementBy!d(' p2"),addEventListener("dblclick ,
handleAHEvents);
1Й document .getElementByld(' p3").addEventListener(‘ mouseover' ,
handleAHEvents);
document getElementByTd('t1").addEventListener(’ keydown",
bandleAHEvents);
.. document.getElementBy!d(' t2").addEventListener("select",
' handleAHEvents);
document.getElementBy!d('button_11),addEventListener("mouseover",
' bandleAHEvents);
74 }
15 function handleAHEvents(evt) {
16 "use strict";
17 alert('An event occurred from element: " +
18 evt.target.id + ". Event type is: " + evt.type);
19 }
20 «./script?
21 «/head?
22
23 «body onload="registerAHEvents()'' style="margin: 1em'?
24 «hl id=“h1“ style="background-color:aqua >Проверка событий«/Ь1>
25 «р id-’p1" style-"background-color.aqua'^Небольшой абзац. (клик)</р>
«р id= p2' style= background-color:aqua ^Небольшой абзац (двойной клик)«/
С Р*
27 <р id="p3" style="background-color.aqua ?Небольшой абзац, (наведение
мыши)«/р>
28 <р style="background-color:aqua">
29 «textarea id="t1" rows="1" cols='5В">(нажатие клавиши)«/textarea?
30 «/p>
31 «p style="background-color:aqua">
32 «textarea id="t2' rows="1" со1з="50"?(выделение)«/1ех1агеа>
33 </p>
34 «button id='Ьи1Юп_1"?Кнопка (наведение мыши)«/button?
35 «/body?
36 «/html?
Когда страница загружается, срабатывает событие onload для элемента body.
Обратите внимание, что здесь префикс on необходим, так как это синтаксис встро-
енного JavaScript (строка 23). Вызываемая функция register AllEvents находит
различные HTML-элементы и регистрирует обработчики событий разных типов
(строки 8-13). Обычно вы регистрируете разные функции, но для упрощения в этом
150
Обработка событий DOM
примере мы регистрируем одну' и ту же функцию handleAHEvents для всех эле-
ментов. Эта функция сообщает тип события и элемент, который его инициировал.
Свойства событий
Событие всегда передается в обработчик событий в качестве первого параметра
в виде объекта JavaScript. Объекты JavaScript состоят из свойств; свойства представ-
ляют собой пары «ключ/значение». В любом случае одним из ключей является type.
Он содержит тип события; некоторые из его возможных значений показаны в табли-
це ниже. В зависимости от типа события доступно множество других свойств.
Вот несколько примеров более или меиее важных свойств.
Название Описание
button Возвращает, какая кнопка мыши была нажата
clienrX Возвращает горизонтальную координату указателя мыши в локальных координатах, прокрученные части не учитываются
clientY Возвращает вертикальную координату указателя мыши в локальных координатах; прокрученные части не учитываются
code Возвращает текстовое представление нажатой клавиши, например, "ShiftLeft" или "КеуЕ'
key Возвращает значение нажатой клавиши, например ' Е"
offsetX Возвращает горизонтальную координату (по X) указателя мыши внутри целевого DOM-элемента
offsetY Возвращает вертикальную координату (по Y) указателя мыши внутри целевого DOM-элемента
pageX Возвращает горизонтальную координату (X) указателя мыши в координатах страницы, включая прокрученные части
pageY Возвращает вертикальную координату (Y) указателя мыши в координатах страницы, включая прокрученные части
- г ее пх Возвращает горизонтальную координату (X) указателя мыши
в координатах всего монитора
sc г eenv Возвращает вертикальную координату (Y) указателя мыши
в координатах всего монитора
target Возвращает элемент, который инициировал событие
Q Возвращает количество миллисекунд между созданием элемента
р и созданием события
removeEventListener
151
Название Описание
type Возвращает тип элемента, который инициировал событие
X Псевдоним для clientX
У Псевдоним для client Y
Пример доступа к свойству приведен в следующем скрипте:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <script>
5 function changeTitle(evt) {
6 "use strict';
7 const xPos = evt.x;
8 const yPos = evt.y;
9 document.title = [xPos, yPos];
10 }
11 </script>
12 </head>
13
«body onmousemove= changeTitle(event)" style="margin:1 ein; border-width:
Ipx; border-style: solid;">
15 <h1 id= hl' style="background-color.aqua'>Проверка событий</Ь1>
<p id="p1' style="margin,2em; background-color:адиа">Небольшой аб-
зац. </p>
«p id="p2" style="margin;2em; background-color :aqua">Eine один неболь-
шой абзац.</p>
18 «button id=‘button_1 ">KHonKa</button>
19 </body>
20 «/html>
Для элемента body регистрируется событие mousemove. Каждый раз, когда
мышь перемещается по body, событие срабатывает. Обработчик событий читает
свойства X/Y из объекта JavaScript и отображает их в заголовке активной вкладки
браузера.
removeEventListener
Аналогично addEventListener функция removeEventListener удаляет обра-
ботчик событий из элемента.
152
Обработка событий DOM
Синтетические события
Система предлагает богатый набор типов событий, показанных выше. Дополни-
тельно вы можете создавать свои собственные события и инициировать их из ваше-
го приложения.
Сначала вы создаете функцию с одним параметром — обработчиком событии.
Затем вы регистрируете этот обработчик событий для элемента. Пока все так же,
как и с предопределенными типами событий:
function register() {
"use strict";
// ...
// выбираем произвольный тип события (первый параметр 'addEventListener')
//и регистрируем функцию на элементе
document.getElementBvIdl"р1").addEventListener( syntheticEvent", f);
}
javascript
Серу
// обработчик событий для несистемного события
function f(evt) {
alert("Invocation of the synthetic event on’ ' + evt.target.id +
" The event type is. " + evt.type);
}
Теперь вы можете инициировать это событие в любой части вашего приложения.
Для этого вы создаете новое событие точно выбранного типа и вызываете его с помо-
щью вызова dispatchEvent:
function triggerEvent(evt) {
"use strict";
// создаем новое событие с соответствующим типом
const newEvent пел Event("syntheticEvent );
// инициируем это событие на элементе рГ
document.getElementById( р1").dispatchEvent(newEvent);
}
Для тестирования мы связываем эту функциональность с кнопкой. Полная стра-
ница теперь выглядит так:
c'DOCTYPE html>
<html>
<nead>
<script>
function register() {
"use strict";
document.getElementBy!d('pl").addEventListener("click", showMessage);
document.getElementById( p2'').addEventListener( click", showMessage);
document.getElementByld(“button_1").addEventListener("click", tnggerEvent);
// выбираем произвольный тип события (первый парамето 'addEventListener )
// и регистрируем функцию на элементе
document.getElementByld("pl").addEventListener( syntheticEvent", f);
}
// обработчик событий для несистемного события
function f(evt) {
"use strict";
alert("Invocation of the synthetic event on: " + evt.target.io +
' The event type is: " + evt.type);
}
(А)синхронное поведение
153
function showMessage(evt) {
"use strict";
// параметр 'evt' содержит много информации
// о событии, например позицию, откуда ино произошло
alert( A click event to element: " + evt.target.id +
" The event туре is: " + evt.type);
}
function triggerEvent(evt) {
''use strict";
// создаем ноиое событие с соответствующим типом
const newEvent = new Event( syntheticEvent");
// инициируем это событие на элементе р1
document.getElemenrById("pl").dispatchEvent(newEvent);
}
</script>
</head>
<body onload="register()">
<h1>Create an event programmatically <Zh1>
<p id="p1“ style="margin‘2ет; background-color :aqua ">A small paragraph.</p>
<p id="p2" styles''margin :2em; background-color :aqua '>Arother small paragraph.</p>
<button id="button_1">Button</button>
</body>
</html>
Вначале кнопка «слушает» события click, и элемент р1 «слушает» события типа
click, а также типа syntheticEvent Когда кнопка нажимается, ее обработчик со-
бытий triggerEvent создает новое событие типа syntheticEvent и инициирует
его на элементе p l (что является основной целью этого примера). Обработчик собы-
тий showMessage показывает сообщение без необходимости клика на pl Другими
словами, событие на pl происходит без клика на pl.
Возможно, вам понадобятся в обработчике событий некоторые данные из вызы-
вающей функции, например, текст сообщения об ошибке, данные HTTP-ответа и т. д.
Вы можете передать такие данные, используя CustomEvent и его свойство detail:
const newEvent = new CustomEvent("syntheticEvent", {detail: "A short message."});
Доступ к данным в обработчике событий:
function f(evt) {
"use strict";
alert("Invocation of the synthetic event on: + evt target.id +
" The event type is + evt type + ". + evt detail);
}
(А)синхронное поведение
Большинство событий обрабатываются синхронно, например click, key
или mouse. Однако есть несколько исключений, которые обрабатываются асинхрон-
но, например load111121. «Синхронный» означает, что последовательность вызовов со-
впадает с последовательностью их создания. Нажатие на кнопку А, В, а затем С при-
водит к вызову обработчиков событий А, В и С именно в этой последовательности.
В отличие от этого, «асинхронные» события могут вызывать связанные с ними обра-
ботчики в произвольной последовательности.
154
Обработка событий DOM
Необходимо отличать вызов обработчиков событий от реализации их тел. Каж-
дая реализация может действовать строго последовательно или содержать асин-
хронные вызовы — это зависит от ваших намерений. Типичными асинхронными
вызовами являются НТТР-занросы или запросы к базе данных. Конечно, они могут
быть частью обработчика события click.
См. также
MDN: Введение
в обработчики со
бытии
(https;//developer.
mozilla.org/en-US/
docs.'Web/Guide/
Events/Event_
handlers)
MDN: Справочник
и типы событий
(https://developer.
moziUa.org/en US/
docs/Web/Events)
W3Schools: События
(www.w3schools.
com/jsref/dom _obj_
event.asp)
W3Schools:
EventListener
(www w3schools.
com/js/js htmldom
evenilistener.asp)
Ссылки
1. W3C: Синхронность
и асинхронность
(hups://w3c.giihub io/
uievents/#sync-async)
2. W3C: Список типов
событий
(https://w3c.github.io/
uievents/#event-types-
list)
Отладка JavaScript
Отладчики JavaScript
Firebug
Firebug (http://www.getfirebug.com/) — это мощное расшире-
ние для Firefox, которое предоставляет множество инструментов
для разработки и отладки, включая отладчик и профилировщик
JavaScript.
Venkman JavaScript Debugger
Venkman JavaScript
Debugger
(www.hacksrus.com/~ginda/
venkman/) (для браузеров
на основе Mozilla, таких
как Netscape 7.x, Firefox/
Phoenix/Firebu’d и Mozilla
Suite 1.x)
Введение в Venkman
(http://web.archive.org/
web/20040704044520/
devedge.netscape.
com/viewsource/2002/
venkman/01/)
Использование точек
останова в Venkman
(http://web.archive.org/
web/20040603085323/
devedge.netscape.
com/viewsource/2003/
venkman/01/)
Отладка в Internet Explorer
Microsoft Script Debugger
(http://msdn.microsoft.com/
library/default.asp?url=/
library/en-us/sdbug/Html/
sdbug_l.asp) (для Internet
Explorer) — отлад-
чик скриптов из эпохи
Windows 98 и NT. Он был
заменен на Developer
Toolbar.
Internet Explorer Developer
Toolbar
(http:/,'www.microsoft.
com/downloads/details.
aspx?FamilyID=2f465beP
94fd-4569~b3c4
dffdfl9ccd99&
displaylang=en)
Microsoft Visual Web
Developer Express
(http:,'/www.m icrosoft.
com/express/vwd/) — бес-
платная версия IDE Visual
Studio от Microsoft.
156
Отладка JavaScript
Включает в себя отладчик JavaScript.
Краткий обзор его возможностей можно
найти здесь:
http:'/www.berniecode.com/
biog/2007/03/08/how-to-debug-javascnpt-
with-visual-web-developer-express/
Internet Explorer 8
(http://www.mici'osoft.com/windows/
Internet-explorer/) имеет встроештый
инструмент для веб-разработки, похо-
жий на Firebug, который можно
открыть, нажав F12.
Этот инструмент также позволяет пере-
ключаться между движками рендерин-
га 1Е8 и 1Е7.
Отладка в Safari
Safari включает в себя мощный набор инструментов, которые упрощают отлад-
ку, настройку и оптимизацию веб-сайтов для достижешгя максимальной производи-
тельности и совместимости. Чтобы получить доступ к этим инструментам, включите
меню «Develop» в настройках Safari. Эти инструменты включают в себя Web Inspector,
консоль ошибок, отключение функций и другие возможности для разработчиков.
Web Inspector предоставляет быстрый и удобный доступ к самому богатому набору
инструментов для разработки из всех когда-либо включенных в браузер. От просмо-
тра структуры страницы до отладки JavaScript и оптимизации производительности
Web Inspector представляет свои инструменты в чистом окне, разработанном для по-
вышения эффективности разработки веб-приложений. Чтобы активировать его, вы-
берите «Show Web Inspector» в меню «Develop». Вкладка «Scripts» включает мощный
отладчик JavaScript в Safari. Чтобы использовать его, выберите вкладку «Scripts»
в Web Inspector и нажмите «Enable Debugging». Отладчик проходит через JavaScript ва-
шей страницы, останавливаясь при обнаружении исключений или ошибочного син-
таксиса. Вкладка «Scripts» также позволяет приостановить выполнение JavaScript,
установить точки останова и оценить локальные переменные1'1.
JTF: Ферма модульного тестирования JavaScript
JTF (http://jtf.ploki.info) — это совместный веб-сайг, позволя-
ющий создавать тестовые случаи, которые будут тестироваться
всеми браузерами.
Это лучший способ выполнять TDD (разработку через тестиро-
вание) и быть уверенным, что ваш код будет работать во всех бра-
узерах.
jsUnit
jsUnit (http://www.jsunit.net/)
Распространенные ошибки
157
Встроенные инструменты отладки
Некоторые предпочитают отправлять сообщения отладки в «консоль отладки»
вместо использования функции alert ():
(http://osieele.com;
archives/2006/03/inline-
console)
(h i tp:/;www .w ebreference.
com/js/columnl 08/5.html)
(http ://www.experts-
exch a nge. com/W eb/
WebLanguages/
J avaScripT/Q_21380186.
html)
Ниже приведен краткий список популярных браузеров и способов доступа к их
консолям/инструментам отладки.
• Firefox: Ct rl+Shif t+K открывает консоль ошибок.
• Opera (9.5-*): Tools >> Advanced >> Developer Tools и открывается
Dragonfly (https://en.wikipedia.org/wiki/Opera_Dragonfly).
• Chrome: Ctrl+Shift+J открывает окно Developer Tools, сфокусированные
на вкладке Console.
• Internet Explorer: F12 открывает инструмент для веб-разработки, похожий
на Firebug, который имеет различные функции, включая возможность
переключения между движками рендеринга IE8 и IE7.
• Safari: Cmd+Alt+C открывает WebKit Inspector для Safari.
Распространенные ошибки
• Внимательно читайте код на предмет опечаток.
• Убедитесь, что каждая " (" закрыта ")" и каждая " {" закрыта "}".
• Запятые в конце объявлений массивов и объектов вызовут ошибку в Microsoft
Internet Explorer, но не в браузерах на основе Gecko, таких как Firefox.
// Объект
var об] = {
foo': bar',
'color': 'red', // лишняя запятая
};
158
Отладка JavaScript
// Массив
var arc - [
foo',
'bar', // лишняя запятая
• Помните, что JavaScript чувствителен к регистру. Ищите ошибки, связанные
с регистром.
• Не используйте зарезервированные слова (Reserved Words) в качестве имен
переменных, функции или меток циклов.
• Экранируйте кавычки в строках с помощью "", иначе интерпретатор JavaScript
подумает, что начинается новая строка, например:
al-etI; Не s eatifKf feed’1. // ошибка
// должно быть
alert( Не\ s eating food'); // или
alert("He s eating food");
• При преобразовании строк в числа с помощью функции parselnt помните,
что "08“ и "09" (например в датах) указывают на восьмеричное число
из-за префикса в виде нуля, Использование parselnt с основанием 10
предотвращает неправильное преобразование.
var n = parselnt(09 , 10);
• Помните, что JavaScript независим от платформы, но не независим от браузера.
Из-за отсутствия строю соблюдаемых стандартов существуют функции,
свойства и даже объекты, которые могут быть доступны в одном браузере,
но недоступны в другом. Например, массивы в Mozilla/Gecko имеют функцию
indexOf (); в Microsoft Internet Explorer она отсутствует.
Методы отладки
Отладка в JavaScript не сильно отличается от отладки в большинстве других язы-
ков программирования.
Отслеживание переменных во время выполнения скрипта
Самый простой способ проверить переменные во время выполнения — это вызов
alert (). Однако некоторые среды разработки позволяют пошагово выполнять код,
проверяя переменные по ходу выполнения. Такие среды могут позволить вам изме-
нять переменные, пока программа приостановлена
Ошибки браузеров
Иногда ошибка заключается в браузере, а не в вашем скрипте.
Это означает, что вам нужно найти обходной путь.
Отчеты об ошибках браузеров (http://mxTV.quirksinode.urg/
bugreports/)
Код, зависящий от браузера
159
Код, зависящий от браузера
Некоторые продвинутые функции JavaScript не работают в некоторых браузерах.
Часто наша первая реакция — определить, какой браузер использует пользова-
тель. а затем сделать что-то крутое, если браузер пользователя поддерживает эту
функцию. В противном случае пропустить это.
Вмести «определения браузера» гораздо лучше написать JavaScript с «обнаруже-
нием объектов», чтобы определить, поддерживает ли браузер пользователя конкрет-
ный объект (метод, массив или свойство), который мы хотим использовать.
Статьи на эту тему:
http://www.quirksmode.
org/js/support.html
http://pageresource.com/
jscript/jobdet.htm
Чтобы узнать, существует ли метод, свойство или другой объект, и выполнить
код, если он существует, мы пишем код следующим образом:
var el = null;
if (document ..getElementByld) {
// современный мегэд
el = document.getElementById(id);
} else if (document.all) {
// старый метод для Internet Explorer
el = document.al1[id];
} else if (document.layers) {
// старый метод для Netscape
el = document.layers[id];
}
Дополнительная литература
«Отладка JavaScript» (http://'www.mozi]la.org/docs/web-developer/
js/debugging/) от Ben Bucksch
Ссылки
1. «Safari — The best way to see the sites» (на английском) (HTML).
Apple. http://www.apple.eom/safari/features.himl#developer.
Оптимизация
Оптимизация JavaScript
Техники оптимизации
• Высокоуровневая оптимизация
о Алгоритмическая оптимизация (математический анализ)
о Упрощение
• Низкоуровневая оптимизация
о Развертывание циклов (Loop Unrolling)
о Снижение сложности операций (Strength Reduction)
о Устройство Даффа (Duff's Device)
о Чистые циклы (Clean Loops)
• Внешние инструменты и библиотеки для ускорения/оптимизации/сжатия
кода JavaScript
Распространенные ошибки и заблуждения
Конкатенация строк
Строки в JavaScript являются неизменяемыми объектами. Это
означает, что после создания строкового объекта для его измене-
ния теоретически должен быть создан другой строковый объект.
Предположим, вы хотите выполнить ROT-13 (https://en. Wikipedia,
org/wiki/ROT-13) для всех символов в длинной строке.
Предположим, у вас есть функция roti 3 (), очевидный способ
сделать это может быть следующим:
var si = "the original string1;
var s2 =
for (i = 0; i < si.length; i++) {
s2 += rot13(sl.charAt(i));
}
Особенно в старых браузерах, т аких как Internet Explorer 6, это будет очень мед-
ленно. Эго связано с тем, что на каждой итерации вся строка должна быть скопиро-
вана перед добавлением нового символа.
Один из способов ускорить этот скрипт — создать массив символов, а затем объ-
единить его:
var si = "the original string’;
var a2 = new Array(s1.length);
var s2 =
Распространенные ошибки и заблуждения
161
for (i = 0; i < si.length; i++) {
a2[i] = rot13(s1.charAt(i));
}
&2 = a2.join('');
Internet Explorer 6 будет выполнять этот код быстрее. Однако, поскольку исход-
ный код настолько очевиден и прост в написании, большинство современных бра-
узеров улучшили обработку1 таких конкатенаций. В некоторых браузерах исходный
код может выполняться быстрее, чем этот.
Второй способ улучшить скорость этого кода — разбить строку, в которую проис-
ходит запись. Например, если это обычный текст, пробел может быть хорошим раз-
делителем.
var s1 = the original string";
var c;
var st = "";
var s2 =
for (i = 0; i < si.length; i++) {
c = rot13(s1.cnarAt(i));
st += c;
if (c == " '') {
s2 += st;
st =
}
}
s2 += st;
Таким образом, основная часть новой строки копируется гораздо реже, так как от-
дельные символы добавляются к меньшей временной строке.
Третий спосиб действительно улучшить скорость в цикле for — вынести выра-
жение [array]. length за пределы условия. На самом деле при каждом выполне-
нии [array ]. length будет пересчитываться. Для двух итераций разница будет не-
заметна, но. например, в цикле с пятью тысячами итераций вы увидите разницу. Эти
можно объяснить простым расчетом:
// предположим, что myArray length равнс 5000
for (х = 0; х < myArray.length, х++) {
// выполнение некоторых действий
}
х = 0 вычисляется только один раз, так что это толькс одна операция.
х < myArray.length вычисляется 5000 раз, гак что это 10 000 операций
(myArray length — это одна операция, и сравнение myArray. length с х —это еще
одна операция).
х++ вычисляется 5000 раз, так что это 5000 операций.
Итого: 15 001 операция.
// предположим, что myArray.length равно 5000
for (х = 0, 1 = myArray.length; х < 1; х++) {
// выполнение некоторых действий
}
х = б вычисляется только один раз, так что это только одна операция.
1 = myArray . length вычисляется только один раз, так что это только одна опе-
рация.
162
Оптимизация
х < 1 вычисляется 5000 раз, так что это 5000 операции (сравнение 1 с х — это одна
операция).
х++ вычисляется 50о0 раз, так что это 5000 операций.
Итого: 10 002 операции.
Таким образом, чтобы оптимизировать ват цикл for, нужно написать код следу-
ющим образом:
var si = "the original string ;
vac c;
var st =
var s2 =
for (i = 0, 1 = si.length; i < 1; i++) {
c = rot13(s1.charAt(i));
st += c;
if (c == “ “) {
s2 += st;
st = ““;
}
}
s2 += st,
Shell
Вы можете экспериментировать с JavaScript в одной из нескольких оболочек
(shell) в интерактивном пакетном режиме. Это означает, что вы можете вводить
JavaScript построчно, и он будет немедленно выполнен; если вы введете выражение,
которое возвращает значение без его присваивания, это значение будет отображено.
Список доступных оболочек можно найти на сайте mozilla.org по ссылкам, указан-
ным в разделе «Внешние ссылки».
Автономная оболочка (Standalone)
Mozilla Firefox использует движок JavaScript Spider Monkey, ко-
торый доступен как автономная интерактивная оболочка для раз-
личных платформ. Вы можете скачать его по адресу: htips://archive.
mozilla.org/piib/firefox/nightly/latest-mozilla-central/
Найдите файл j sshell- *. zip. Распакуйте его и запустите команду " j s" из ко-
мандной строки. Появится промпт:
js>
Вы можете вводить выражешш пи одному:
js> function incr(i) { return i+1; }
js> incr(i)
2
js> function plus2(i) {
return i+2;
}
js> plus2(1)
3
js> incr
function incr(i) { return i+1; }
js> print ("1+1:"+incr(1))
i+1:2
js> console.logC'Yep ") // Консоль доступна
Yep
Многострочные определения функций можно вводить построчно, нажимая
Enter после каждой строки.
Для выполнения фрагментов JavaScript, использующих функцию alert — по-
скольку они предназначены для веб-браузеров, — вы можете определить свою функ-
цию alert:
js> function alert(messEge) { print ("Alert: "+message); }
В браузере
Вы можете использовать интерактивный режим, вводя JavaScript построчно и не-
медленно выполняя его, прямо из вашего веб-браузера.
164
Shell
Во многих версиях Firefox нажмите Ctrl + Shift + К, чтобы открыть веб-кон-
соль. Внизу окна консоли есть отдельное однострочное поле, в которое вы можете
вводить строки JavaScript и выполнять их, нажимая Enter. Даже многострочные
определения функций можно вводить, но не нажимая Enter, а используя Shift +
Ente г, и нажимая Enter только после завершения всего определения.
Внешние ссылки
Введение в оболоч-
ку JavaScript
(https://developer.
mozilla.org/
еп-US/docs/
Mozill а/Projects/
SpiderMonkey/
Introduction, to the_
JavaScnpt_shell),
developer.mozilla.
org
Оболочки
JavaScript
(https://developermozilla.org/en-US/
docs/Web/JavaScnpt/
Shells), developer
mozilla.org
Скорость движков
JavaScript
(htup://ejohn org/
bl og/java script -
engine-speeds/),
ejohn.org
Интерактивная
оболочка JavaScript
с автодополнением
(http://stackoverflow.
com/questions/41207/
javascript-
interactive-shell-
wiih-completion),
stackoverflow.com
Формы
Многие пользователи знакомы с заполнением форм: на веб-странице и последую-
щим нажатием кнопки «отправить» (submit). Существует как минимум два способа,
с помощью которых JavaScript может улучшить этот процесс:
• JavaScript может быть использован для проверки данных перед их отправкой
па сервер.
о JavaScript может предварительно проверять данные, чтобы выявлять рас-
пространенные ошибки и предлагать улучшения сразу же, пока пользова-
тель заполняет форму, до того как он нажмет кнопку «отправить».
с JavaScript может взять текст, введенный в текстовое поле (text area), и пред-
варительно отобразить его в отдельной области страницы, чтобы пользо-
ватели могли видеть, как он будет отформатирован и отображен, перед на-
жатием кнопки «отправить» (submit)111121131.
с JavaScript может предоставлять «живой» подсчет слов или символов
для текста, введенного в текстовое поле141151161171.
• Иногда веб-сайт выполняет онлайн-расчет, который включает только неболь-
шое количество данных, и возвращает результат пользователю. В этом случае
JavaScript может опередить кнопку «отправить» и выполнит]» весь расчет ло-
кально в браузере. Пользователь получает результат практически мгновенно,
вместо того чтобы ждать отправки данных на сервер, ожидания обработки
данных сервером и получения результата обратно.
Многие рекомендуют сохранять весь контент доступным для людей с ограни-
ченными возможностями и для тех, у кого отключен JavaScript. Один из способов
сделать это — начать со стандартных HTML форм, а затем добавить ненавязчивый
JavaScript для улучшения пользовательского опыта для тех, у кого JavaScript вклю-
чен. Система должна деградировать корректно, сохраняя весь контент доступным
(и проверяя данные пользователя, если необходимо), независимо от того, выполня-
ется ли JavaScript успешно или нет.
Ссылки
1. «How can I display the HTML content of a Text Area within a div as
HTML content and not text?»
(http://stackoverflow.com/questions/1323812/how-can-you-render-
himl-as-it-is-typed-into-a-textarea)
2. Andrey Fedoseev. «jQuery plugin to add realtime preview panel to
text areas, similar to Stackoverflow edit interface»
(http://andreyfedoseev.name/en/blog/post/34/jquery-textareapreview)
166
Формы
3. Guillaume DE LA RUE. «А Markdown live editor in JS»
(hrtp:/,'www.js2node.corn/markduwn/a-markdown-live-editor-in-js)
4. Sacha Schmid. «JavaScript word count»
(http://radlikewhoa.gi thub.io/Countable/)
5. Drew Schrauf. «JavaScript Wordcount That Works»
(http://drewschrauf.com/blog/2012/06/13/javascript-wordcount-that-
works/)
6. «JavaScript word-count for any given DOM element»
(http://stackoverflow.com/questions/765419/javascript-word-count-for-
any-given-dom-element)
7. Jake Rocheleau «Building a Live Text area Character Count Limit
with CSS3 and ]Query»
(http://spyrestudios.coni/building-a-live-textarea-characier-count-
l imit-with-css3-and-j query/)
Букмарклеты (Bookmarklets)
Букмарклеты (bookmarklets) — это однострочные скрипты, которые хранятся
в поле URL закладки. Букмарклеты существуют уже давно, поэтому они работают
даже в старых браузерах.
Схема URI JavaScript
Вы должны быть знакомы с URL, которые начинаются с таких схем, как http и ftp,
например https://ru.wikipedia.org/. Существует также схема JavaScript, которая исполь-
зуется для запуска каждого букмарклета:
JavaScript:alert('Hello. World1');
Примеры использования
Управление медиа
Значения в этих примерах можно адаптировать по желанию. Можно заменить
video на audio, где это применимо, то есть где встроен тег <audio>.
Зациклить видео
javascriptrdocument.getElementsByTagName("video )[0J loop=1;
javascript;docdrient.getElementsByTagName("video )[0].loop-true; // также работает
Можно отключить, используя 0 или false.
Перейти к десяти минутам (с использованием умножения)
javascript:docunient.getElenientsByTaqNaire( "video ) Г и I. current! ime=60*10;
Перейти вперед на одну минуту (шестьдесят секунд)
javascript document.getElementsByTagName("video )[0] cur rent!ime+=b0;
Перейти назад на полминуты (с использованием деления)
javascript document.getElementsBylagNaire/"video )[0J. currentTlme-=b0/2;
Получить продолжительность видео на странице в консоли
javascript:docunient.getElenientsByTagNan:e("video )fo] duration
Вывести продолжительность в alert
javascript:alert('This video is '+docun,ent.getElementsByTagName("video")[Q].
duration+ seconds long ')
168
Букмарклеты (Bookmarklets)
Вывести текущее время воспроизведения
javascript:alert(‘The current position of the video is at '+document.
getElementsByTagName("video')[0].currentTime+ seconds.')
Установить громкость звука на 50%
javascript:document.getElementsByTagName("video')0 J.volume-50/100
Отключить звук
javascript document.getElementsByTagNaire( "video" )[й] muted=1 // "true" также работает
Включить звук, используя 0 или false
Удвоить скорость воспроизведения
javascript:document.getElements8yTagName("video )101.playbackRate=2
Запросить скорость воспроизведения
javascript document.getElements5yTagName("video )[0].playbackRate= parseFloat(
prompt( How fast should it play’’") );
pa rseFloat необходим, чтобы предотвратить присвоение значения в ноль, если
окно диалога закрыто без ввода пользователя.
Запросить позицию воспроизведения в секундах
javascript document.getElementsByTagNamef"video )[0].currentTime=parseFloat(
prompt('Jump to playback position in seconds:") );
Запросить позицию воспроизведения в минутах
javascript document.getElementsByTagNamef"video )0 ] .current!ime*60*parseFloat(
prompt( Jump to playback position in minutes:") );
Запросить позицию воспроизведения в процентах (от 0 до 100)
javascript:document.getElementsBylagName( " video )J 0].currentTime=document.
getElementsBy7agName("video")[t],duratJon/100*parseFloat( prompt("Jump to playback
position in percents:") );
Использование нескольких строк кода
Поскольку в букмарклетах нельзя использовать разрывы строк, вы должны ста-
вить точку с запятой в конце каждого оператора кода:
JavaScript:name-prompt('What is your name9'); alert('Hello, ' + name);
Протокол JavaScript в ссылках
169
Протокол JavaScript в ссылках
Протокол JavaScript можно использовать в ссылках. Это может считаться пло-
хой практикой, так как это затрудняет доступ или сбивает с толку пользователей, от-
ключивших JavaScript:
<а href="JavaScript document.bgColor='ff0300FF'">blue background</a>
Примеры
Большое количество ссылок можно найти на bookniarklets.com
(htip:/'www.bookmarklets.com/), они демонстрируют различные
функции, которые можно выполнять с помощью JavaScript.
Работа с файлами
С использованием чистого HTML4 и чистого JavaScript единственный способ рабо-
ты с пользовательскими файлами показан ниже.
Сервер отправляет веб-страницу, которая включает форму, подобную этой111:
«form acticn="/upload_handler nethod= post">
«input type= file" />
</form>
Затем браузер позволяет пользователю выбрать один файл, и браузер загружает
его — без возможности для JavaScript на стороне клиента «увидеть» какие-либо дан-
ные, отменить передачу или даже показать индикатор прогресса.
Если вы хотите, чтобы JavaScript мог «узнать» что-либо о файле до его переда-
чи (например, чтобы немедленно отменить передачу большого файла, вместо того
чтобы ждать час для завершения передачи, а затем сообщить пользователю «Файл
слишком большой»: или чтобы показать индикатор прогресса), вам придется исполь-
зовать что-то другое, кроме чистого JavaScript и чистого 11TML4.
Некоторые популярные варианты'21131141151:
1. Использовать современный веб-браузер, который поддерживает HTML5 File
API.
2. Использовать Flash (возможно, небольшое Flash-приложение, как то, что
использует Gmail для отображения индикатора прогресса)
3. Использовать Java-апплет.
4. Использовать ActiveX-контроль.
Ссылки
RFC 1867
(h ttp s: /I da t atr a ck er.let f.
org/doc/html/rfcl 867)
RFC 2388
(https://dalatracker.ietf.
org/doc/html/rfc2388)
2. Получение размера файла перед загрузкой
(http://stackoverflow.com/questions/4190934/getting-upload-file-size-
before-upload)
Ссылки
171
3. Возможно ли использовать Ajax для загрузки файлов?
(http://stackoverflow.com/questions/543926/is-it-possible-to-use-ajax-
ro-do-file-upload)
4. Tile API: W3C Last Call Working Draft 12 September 2013
(http://www.w3.org/TR/FileAPI/)
5. Чтение файлов в JavaScript с использованием File APIs
(http://www.html5rocks.com/en/tutorials/file/dndfiles/)
Обработка XML
Простая функция для открытия ХМЬфайла
Эта функция сначала пытается использовать Microsoft Internet Explorer, затем
Firefox и другие браузеры:
function lcaaXMLDoc(xmlfilename) {
var event = new Error();
11 Internet Explorer
try {
var xmlDoc = new ActiveXObject( Microsoft. XMLDCM'');
} catch(event) {
// Firefox, Mozilla, Opera, другие
try {
xmlDoc = document.implementation.createDocument("", ’"'.null);
} catch(event) {
throw(event.messaqe);
}
}
try {
xmlDoc async = false;
xmlDoc.load(xmlfilename);
return(xmlDoc);
} catch(event) {
throw(event.message);
}
return(null);
}
Использование
var objXML = loadXMLDcc("filename.xml");
var chlodes = objXML.getElementsBylagName( 'AnyTagYoulfrish");
Теперь вы можете выполнять любые операции с DOM (Document Object Model)
на объекте oNudes.
Изменения в XML нельзя сохранить с помощью JavaScript, так как это сторона
клиента.
Обработка JSON
Нативная поддержка JSON
Современная обработка JSON может потребовать добавления поддерживающей
библиотеки, которая создает глобальный объект JSON. Этот объект присутствует на-
тивно только в новых браузерах (например, FF 3.5, IE8):
// Парсинг JSON:
var myObject = JSCN.parse(myJSONtext);
// Создание JSON:
var myJSONText. = JSON.stringsfy(myObject);
Старый способ
В старых браузерах можно использовать следующий синтаксис, но это может вы-
звать проблемы с безопасностью, такие как XSS:
var myObject = eval("(" + myJSONtext +
JSONP
Учитывая ограничения браузеров на кросс-доменные Ajax-запросы (разрешен-
ные только через настройку в некоторых ранних браузерах, нестандартными сред-
ствами в IE8 и с помощью заголовков сервера в HTML5), одним из способов обхода
таких ограничений (при этом все же требующим некоторой координации на сторо-
не сервера) является динамическое вставление HTML-тега script в код сайта. В этом
случае кросс-доменный скрипт, как правило, предоставляет JSON, но обернутый в вы-
зов функции (имя функции указывается в параметре "callback", передаваемом за-
прашивающей стороной) или другой исполняемый код.
В РНР можно предоставить такой JSONP следующим образом:
<?рпр
if (isset($_GET['callback'])) {
header( Content-Type: application/javascript');
$.-or_site_data = ... // Установите массив или объект, содержащий данные для ис-
пользования на других сайтах
print $_GET['callback'] . '(' json_encode(Sour_site_data) . ')';
}
?>
jQuery и другие фреймворки имеют свои собственные средства для генерации
JSONP-запросов, но мы используем следующий пользовательский код.
Примечание: важно помнить, что следующий код не следует использовать, если
целевой сайт или данные, предоставляемые целевым сайтом, могут поступать из не-
надежного источника, так как такие скрипты могут выполняться с привилегиями
использующего сайта (например, читать пользовательские куки и передавать их
на другой сайт) и, таким образом, выполнять а гаку межсайтового скриптинга (XSS).
174
Обработка JSON
<script>
var JSONP = function(global) { // Вводит только один глобальный объект
// Лицензия MIT, адаптировано из http://devpro.it/code/209.html
function JSONP(uri, callback) {
function JSONPResponse() {
// Уменьшаем использование памяти, удаляя копбзки после завершения
try { delete JSONP[src] } catch(e) { JSONP[$rc] = null; }
aocumentElement.removechild(script);
// Выполняем пользовательский колбэк с аргументами, предоставленными сер-
вером в JSONP-вызове
if (typeof callback === 'string') { // Предполагаем, что возвращаемый ар-
гумент только один и что это HTML-строка
document.gelElementByld(calloack).innerHTML = arguments^];
} else {
callback apply(this, arguments);
}
}
// Обеспечиваем уникальный колбэк
var src = + id++,
script = document.createElement(''script') ;
// Добавляем наш колбэк как свойство этой функции JSONP
// чтобы избежать введения дополнительных глобальных переменных
JSCNP|src] = JSONPResDonse;
11 Включаем "callback", так как он обычно используется
// в JSONP (например, е API WiKiboeks) для указания колбэка
documentElement insertBetore(
script,
documentElement.lastChild
).src = uri + (uri.indexOf( ? ) === -1 ? '? ’&') + ''callback=JSONP " + src;
}
var id = 1, documentElement = document.aocumentElement;
return JSONP;
}(this);
// Получаем разобранный HTML страницы,
// используя API Mediawiki (см. http://en.wikibooks.Org/w/api.php
// для Wikibooks, но это также применимо и к другим вики на Mediawiki), который
// позволяет выполнять такие кросс-доменные запросы
JSONP('http://en.wikibooks org/w/api.php?action=parse&f ?rmat=jsun&page=JavaScript/
Hanoling._jSON ,
function (oata) {
alert(data.parse.text['*']);
}
);
</script>
Дополнительная информация
Использование натив-
ного JSON в Tiretox
(https://developerniozilla.org/En/Using_
native.JSON)
Использование натив-
ного JSON в IE8
(http://blogs.msdn.com/
ie/archive/2008/09/10/
native-json-in-ie8.aspx)
CS Communication
Во многих случаях взаимодействие между клиентами и серверами программиру-
ется на JavaScript. Эти ]8-скрипты используют основные и расширенные возможности
языка, особенно еги асинхронные функции. Для реализации такого взаимодействия
нет необходимости вводить какие-либо специальные или дополнительные функции
в сам язык. Однако существуют некоторые термины, библиотеки и API, специфичные
для этого взаимодействия, а именно: термин Ajax, объект XMLHttpRequest, библио-
теки, такие как jQuery или Axios, и Fetch API. Из-за их важности существуют отдель-
ные книги, описывающие их поведение и применение. Данная книга предоставляет
лишь обзор их значимости, краткие описания и ссылки на соответствующие страни-
цы для дальнейшего чтегшя.
XMLHttpRequest
Доминирующим протоколом для взаимодействия между кли-
ентом и сервером является HTTP(S) (https://developer.mozilla.org/en-
US/docs/Web/HTTP).
Он предоставляет команды для чтения данных с сервера (GET)
иизменения данных на сервере (POST, PUT, PATCH, 0Е1_ЕТЕ).Такие ко-
манды передаются внутри объекта, называемого XMLHtt pRequest.
Он также содержит содержимое (данные) для обоих направлений:
к серверу и ог сервера. В настоящее время данные в основном фор-
матируются в JSON — несмотря на название XMLHttpRequest, ко-
торое указывает на изначально используемый формат XML.
Как работать с объектом XMLHttpRequest, описано в:
MDN: XMLHttpRequest
(h ttps ://dev e I oper. nu jzilla.
(irg/en-US/'d ocs/Web/API/
XMLHttpRequest)
Wikipedia:
XMLHttpRequest
(hups://en.wikipedia.org/
wiki/XMLHttp Request)
W3Schools:
XMLHttpRequest
(hups:/,'www.w3schools.
com/xmhxml_http.asp)
Ответ (данные), возвращаемый XMLHttpRequest, может содержать фрагменты
HTML или другую информацию, котирая используется для локального создания фраг-
ментов HTML, например, данные из базы данных, которые должны быть отображены
в HTML-та б лице. Поэтому он является, среди прочего, краеугольным камнем для реа-
лизации одностраничных приложений (SPA).
Непосредственная работа с XMLHttpRequest не устарела, но является устарев-
шей техникой, где необходимо учитывать множество деталей. Библиотеки, основан-
ные на XMLHttpRequest и других API. могут упростить вашу работу.
176
CS Communication
Ajax
Асинхронное поведение протокола HTTP настолько важно, что оно нашло свое
отражение в одном из центральных терминов, «Асинхронный JavaScript и XML,
или Ajax, сам по себе не является технологией, а скорее подходом к использованию
ряда существующих технологий вместе, включая HTML или XHTML, CSS, JavaScript,
DOM, XML, XSLT и, что наиболее важно, объект XMLHttpRequest»111.
Короткие примеры можно найти на следующих сайгах:
MDN: Ajax Introduction
(httpsj/developer.mozilla.
о rg/en-US/d о cs,'W eb/G aide/
AJAX/Gett ing_ Started)
Wikipedia: Ajax
(https://en.wikipedia.org/
wiki/Ajax_programming)
W3Schools: Ajax examples
(https://www.w3schools.
co m/j s/j s_aj ax_php .a sp)
Библиотеки
jQuery — это библиотека JavaScript, которая упрощает часто используемые действия,
такие как навигация и манипуляции с D0M, обработка событий и взаимодействие меж-
ду юшентим и сервером. Вы можете найти больше информации и примеров на:
jQuery Website
(https ://j query .com/)
Wikipedia: jQuery
(https://en.wikipedia.org/
wikl/jQuery)
W3Schools: jQuery
(https://www.w3schools
com/j query/)
Axios — это библиотека JavaScript. Она реализует клиент для браузеров
и для веб-сервера node.js. Axios поддерживает промисы (promises).
Сайт Axios
(https://axios-http.com/)
Digital Ocean. Axios Tutorial
(https://www.digitalocean.com/
commun ity/tut or ials/j s-axios-van ilia -j s)
Fetch API
177
Fetch API
Fetch API поддерживает те же функции, что и устаревший
объект XMLHttpRequest и его интерфейс. Это совершенно но-
вая реализация (с некоторыми незначительными отличиями
от XMLHttpRequest), которая доступна во всех современных бра-
узерах; нет необходимости в использовании дополнительных
библиотек или фреймворков. Она является частью семейства
Web API (hnps://developer.niozill<a.<>rg/en-US/docs/Web/API) (service
worker. DOM API, cache API,...).
Несмотря на свое название fetch, она не только читает данные с сервера. НТТР-ко-
манды, такие как PUT, POST или L Е LETE, также поддерживаются.
Больше информации можно найти на:
MDN: Fetch API
(https://developer.mozilla.org/en-US/
docs/Web/API/Fetch_API)
W3Schools: Fetch API
(https://www.w3schools.coni/js/is_api_
fetch.asp)
Вот структура скрипта:
fetch('https7/jsonplaceholder.typicode.com;users') И пример страницы
,then((response) => { return response.json() }) // извлечение json-часги
.then((users) => { console.log(users) }) // вывод результата
catch((err) => console.log( Some error occurred: + err.message));
Команда fetch запрашивает пример страницы. Эта страница всегда возвращает
массив из десяти адресов в формате json. Первый then извлекает json-часть из ре-
зультата, а второй then выводит ее в консоль. Если происходит ошибка (сеть, опечат-
ка в URL,...), выполняется часть catch и выводится сообщение об ошибке.
Ссылки
1. MDN: Ajax (hitps://developer.mozilia.urg/en-US/docs/Web/Guide/
AJAX)
Глоссарий
Мы стараемся сохранять единообразие в использовании технических терминов
в рамках данной книги. Поэтому ниже приведен краткий глоссарий.
Объект (object) Объект — это ассоциативный массив с парами «ключ- значение» Пары называются свойствами. Все типы дан- ных являются производными от объекта, за исключением примитивных типов данных.
Свойство (.property) Пара «ключ-значение», которая является частью объекта. Ключ — это строка или символ, а значение — это значе- ние любого типа.
Точечная нотация (dot noiation) Синтаксис для идентификации свойства объекта с ис- пользованием точки: myObject. proper tyKey,
Скобочная нотация (bracket noiation) Синтаксис для идентификации свойства объ- екта с использованием квадратных скобок: myOb]ect['propertyKey"].
Фигурные скобки (curly braces notation) Синтаксис для выражения объекта «литерально» с ис- пользованием { }: const myObject = {age: 39); Функция — это блок кода, который вводится с помощью ключевою слова function, необязательного имени, от- крывающей скобки, необязательных параметров и закры- вающей скобки. function greeting(person) { return "Hello ' + person; };
Функция (function) Вышеприведенная функция является именованной. Если вы опустите имя функции, она будет называться аноним- ной функцией. В этом случае существует альтернативный синтаксис с использованием стрелочного синтаксиса =>. function (person) { // нет имени функции return "hello " + person; }; // стрелочный синтаксис. Здесь только опреде- ление функции. // Она не вызывается, поэтому не выполняется, (person) => { return "Helle " + person;
Ссылки
179
Продолжение таблицы
// или (person) => {return "Hello + person}; // присвоим определение переменной, чтобы мож- но было вызвать. let х = (person) => {return "Hello " + person}; // .и выполним анонимную функцию, вызвав переменную, // которая на нее ссылается: х(...) alert(x("Mike")) ; // интересно. alert(x); // выполнение анонимной функции напрямую ((person) => { alert("Hello " + person); })("Mike") ;
Метод (method) Метод — это функция, хранящаяся в виде пары «ключ- значение» в объекте. Ключ представляет имя метода, а значение — гело метода. Метод мижет быть определен и доступен с помощью следующего синтаксиса’ let person = { firstName: Tarek", city : "Kairo", show : function() { return this.firstName + " lives in " + this.city; }, }; alert(person.show());
Функция обратно- го вызова (callback function) Функция, которая передается в качестве аргумента другой функции.
Консоль (console) Каждый браузер содержит окно, в котором отображает- ся внутренняя информация. Оно называется консолью и обычно не открыто. В большинстве браузеров консоль можно открыть с помощью функциональной клавиши F12.
Элемент (element) Отдельное значение в массиве
180
Глоссарий
Окончание таблицы
Параметр (parameter) При определении функции переменные могут быть объ- явлены в ее сигнатуре, например: function f(paraml, param2)
Аргумент (argument) Эти переменные называются параметрами. При вызове функции переменные могут быть указаны для обработки в функции, например: f(arg1, arg2) Эти переменные называются аргументами. Аргументы за- меняют параметры, которые использовались при опреде- лении функции.
Полезные инструменты для
программистов на JavaScript
Список полезных инструментов для программистов на JavaScript.
Редакторы / IDE
Adobe Brackets: еще один браузерный редактор от Adobe
(https://en.wikipedia.org/wiki/Adobe,Brackets).
Eclipse: IDE Eclipse включает редактор и отладчик для JavaScript
(https://en.wikipedia.org/wiki/Eclipse_(software)).
N otepad++ (https://notepad-plu s-plus. org/):
отличный инструмент для редактирования любого вида кода.
Включает подсветку синтаксиса для многих языков программи-
рования.
Programmers' Notepad (https://www.pnotepad.org/):
универсальный инструмент для программирования на различ-
ных языках.
Scripted (https://github.com/scripted-edi1or/scripted):
открытый браузерный редактор от Spring Source.
Sublime Text (https://en.wikipedia.org/wiki/SublimeText):
один из самых популярных редакторов для редактирования
HTML/CSS/JS.
182
Полезные инструменты для программистов на JavaScript
WebStorm (https://en.wikipedia.org/wiki/WebStorm).
Intelli] IDEA (https:/7en.wikipedia.org'wiki/IntelliJ_]DEA).
Обе IDE включают редактор и отла/ршк для JavaScript. Intelli] IDEA также предо-
ставляет платформу для разработки на Java.
Движки и другие инструменты
JSLint (https://en.wikipedia.org/wiki/Jslint):
статический анализ кода для JavaScript.
iq (http://stedolan.github.io/jq/) — <qq — это как sed ддя даштых
JSON».
Список .движков ECMAScript
(https://en.wikipedia.org/wiki/LisLof_ECMAScript_engines).
Лучшие практики
В этой главе описываются текущие стандарты и лучшие практики сообщества
JavaScript, которые должен знать каждый программист.
document, write
Этот метод устарел. Вместо него используйте innerHTML
или методы манипуляции DOM (Document Object Model).
В XHTML document .write не работает, но тех же эффектов
можно достичь с помощью методов манипуляции DOM (http://
w3.org/MarkUp/2004/xhtml-faqffdocwrite).
JavaScript-протокол
Старайтесь избегать ссылок, которые существуют исключительно для выполне-
ния JavaScript-кода:
<а nref'="javascript:resumpFancyVersion()">See my resume!</a>
Вместо этого рассмотрите следующий вариант:
<а href-"resumePlainVersion.html" onclick-'Teturn 1resumeFancyVersion() >See my
resume1</a>
Пользователи с включенным JavaScript получат версию контента с использова-
нием JavaScript (возможно, с DHTML), тогда как те, у кого JavaScript отключен, будут
перенаправлены на XHTML-страницу, предоставляющую контент статически. Это
более доступно, чем использование элемента <а> без нормального значения атри-
бута href. Во-первых, это использует правилыгую семантику языка. Во-вторых, это
обеспечивает доступ к вашему контенту для пользователей без JavaScript. В-третьих,
это проверяет, успешн-i ли выполнилась функция, и перенаправляет пользователей
с включенным JavaScript в случае неудачи.
Выражение onclick возвращает логическое значение. Если функция успешно
выполняет желаемое действие и возвращает true, onclick вернет false, и ссыл-
ка не будет выполнена. Если функция по какой-либо причине завершится неудачно,
значение false, null или undefined будет интерпретировано как true, и ссылка
будет выполнена. В качестве альтернативы, если вы не хотите предоставлять стати-
ческий эквивалент, вы можете встроить атрибут onclick в элемент с менее строгой
семантикой:
<srrong onclick="resumeFancyVersion()">See my resume'</strong>
Таким образом, ни один пользовательский агент не будет запутан при чтении со-
кращенного элемента <а>.
184
Лучшие практики
Валидация email
Многие используют JavaScript-функции для немедленного выявления наибо-
лее распространенных ошибок при вводе данных в формы Например, некоторые
веб-формы просят пользователей ввести одно и то же дважды. Другие формы просят
ввести адрес электронной почты. Затем они выполняют быструю проверку, чтобы
убедиться, что введенные данные хотя бы отдаленно напоминают email:
function isValidEmail(string) {
// Эти комментарии используют следующие термины из RFC2822:
// local-part, domain, domain-literal и dot-atom.
// Содержит ли адрес local-part, за которым следует а затем domain?
// Обратите внимание на использование lastlndexOf для поиска последнего © - адресе,
// так как допустимый email может содержать кавычки в Ijcal-part.
// Содержит ли доменное имя хотя бы две части, т.е. хотя бы одну точку
// после @? Если нет, является ли это domain-literal?
// Этот код примет некоторые недопустимые email-адреса,
// но не отвергнет допустимые
var atSym = string lastlndexOf('©");
if (atSym < 1) { return false; } // нет local-part
if (atSym == string length - 1) { return false; } // нет domain
if (atSym > 64) { return false; } // в local-part может быть только 64 октета
if (string.length - atSym > 255) { return false; } // в domain может быть только
255 октетов
// Правдоподобен ли domain7
var lastDot = string.lastlndexCf(".");
// Прчэерка, является ли это dot-atom, например example.com
if (lastDot > atSym + 1 && lastDot < string length - 1) { return true: }
// Проверка, может ли это быть domain-literal.
if (string.charAt(atSyn + 1) == '[ && string.charAt(string.length - 1) -= ']') {
return true; }
return false;
}
К сожалению, некоторые другие функции валидации email на JavaScript отверга-
ют совершенно допустимые адреса. Например, некоторые ошибочно отвергают допу-
стимые адреса, содержащие знаки ' +
Оригинальный синтаксис email (RTC 821) действительно допускал знаки " + ".
RFC 822, опубликованный в том же месяце (август 1982 года), также их допускал. Те-
кущая версия синтаксиса приведена в RFC2821 (http://www.faqs.org/rfcs/rfc2821.html)
и RFC2822 (http://www.faqs.org/rfcs/rfc2822.html).
Валидация email
185
Раздел 3 RTC3696 (http://'v.rww.faqs.<'jrg/rfcs/rfc3696.html) содержит полезные приме-
ры необычных, но допустимых етай-адресив.
После валидации многие программисты кодируют email с помощью
encodeURIComponent (), чтобы обойти проблемы с некоторыми клиентскими язы-
ками, которые не могут корректно обрабатывать знаки
Сложность правил кавычек, используемых для email-адресов, делает непрактич-
ным полное тестирование локальной части адреса или domain lite ral. Учитывая,
что не обязательно существует реальный почтовый ящик, соответствующий допу-
стимой локальной части, сколько дополнительного времени за1рузки стоит тратить
на сложный скрипт валидации?
Примеры допустимых адресов согласно RFC2822:
• me@example.com
• a.nonymous@example.com
• name+tag@example.com
• a.namei-tag@example.com
• me ,example@com
• 'spaces must be quoted"@example.com
• !#$%&’*+-/».?*_'{|}~@[1.0.0.127]
• !#$%&'*+-/=.?A_'{|}~@[IPv6:0123:4567:89AB:CDEF:0123 4567189AB:
CDEF]
• me(this is a comment)@example.com - комментарии не рекомендую гея,
но не запрещены RFC2822 .
Примеры недопустимых адресов согласно RFC2822:
• те@
• @ехатр1е.сот
• me.@example.com
• .me@example.com
• те@ехатр1е..сот
• те\@ехатрle.com
• spacesX must\ be\ withinX quotes\ even\ when\ escaped@example.
com
• a\@mustbeinqijotes@example.com
Тестовая страница
КОММЕНТАРИЙ: Этот код был некорректно разработан для отклонения некото-
рых email-адресов, которые на самом деле допустимы. Если изменения в допустимых
и недопустимых email-адресах принимаются, следующий код также должен быть пе-
ресмотрен.
186
Лучшие практики
Следующая тестовая страница может быть использована для тестирования функ-
ции валидации email. Сохраните три файла в одной директории и затем откройте
validEmail. html в веб-браузере.
validEmail. js
function isValidEmail(string) {
// Эти комментарии используют следующие термины из RFC2822:
// local-part, domain, domain-literal и uot-atom.
// Содержит ли адрес local-part, за которым следует @, а затем domain7
// Обратите внимание на использование lastlndexOf для поиска последнего @ в адресе,
// так как допустимый email может содержать кавычки в local-part.
// Содержит ли доменное имя хотя бы две части, т.е. хотя бы одну точку,
// после @? Если нет, является ли это domain-literal7
// Этот код примет некоторые недопустимые email-адреса,
// но не отвергнет допустимые
var atSym = string lastlndexOf( @");
if (atSym < 1) { return false; } // нет local-part
if (atSym == string.length - 1) { return false; } // нет domain
if (atSym > 64) { return false; } // в local-part может быть только 64 октета
if (string.length - atSym > 255) { return false; } // в domain может быть только
255 октетов
// Правдоподобен ли domain7
var lastDot = string.lastlndexOf(".");
// Проверка, является ли эго dot-atom, например example.com
if (lastDor > atSym + 1 && lastDot < string.length - 1) { return true; }
11 Проверка, может ли это быто domain-literal.
if (string.charAt(atSym + 1) =- '[' && string.charAt(string.length - 1) == ']') {
return true; }
return false;
}
function testlsValidEmail(stnng) {
alert(... + string + " ' is + (isValidEmail(string) ? 1 : 'NOT ") + " a valid
email address.");
}
function checkSamples() {
var validAddress = [
'me@example.com ,
'a.nonymous@example com',
' name+tag@example.com',
name\\@tag@example.com ,
spacesW are\\ allowed@example com',
spaces may be quoted ^example.com',
'!#$%&\ *+-/=.?A_{|}~@[1.0.0.127]',
•!#$%&\ *+-/=.?*_ {|}~@[IPv6 0123:4567:89AB CDEF-0123:4567 89AB:CDEF]',
'me(this is a comment)@example.com'
var invalidAddress = [
'me@',
^example.com',
'me.@example.com ,
'.me@example.com1,
'me@example..com ,
' me ,example@>com',
me\\@example.cori'
Ьалидация email
187
var results = new StringBuffer();
var handlesValidAddressesCorrectly = true;
results,append('«table border="1;
results append( «caotion>Does the function accept all the valid sample addresses^/
captior»');
results.append). '<tr><th>Valid address</th>«th>Function returns«/th></tr>');
for (var i = 0; i < validAddress.length; i++) {
results.append('<tr><td>');
results.append(valioAdd^ess[iJ);
results.append)'</td>«td> );
if (isValidEmail(validAddress)!])) {
results.append('«span class= gccd >true«/span>');
} else {
handlesValidAddressesCorrectly = false;
results.append)'«strong class="fail">false</strong> ),
}
results.append('</td>«/tr>‘);
}
results append) </'table> );
var handlesInvalidAddressesCorrectly = true;
results.append) «table border="1 >');
results.append)'<caption>Does the function reject all the invalid sample addresses^/
caption>‘);
results.append)' <tr>«th>Valid address«/th>«th>Function returns«/th></tr>');
for (var 1 = 0; i « invalidAddress.length; i++) {
results,append('<tr><td>');
results.append)invalidAddress[ i ]);
results.append)'</to>«td>');
if (!isValidEmail(invalidAddress[i])) {
results.append)'«span class= good >false«/span> );
} else {
handlesInvaljdAddressesCorrectly = false;
results.append)' «em class=''warning' >true</em>');
}
results.append)'</td>«/tr>');
}
results.append)'</table>');
var conclusion;
if (handlesValidAddressesCorrectly) {
if (handlesInvalidAodressesCcrrectly) {
conclusion = '«p>«strong class= gocd >The function works correctly with all the
sample addresses.</stror‘g>«/p>';
} else {
conclusion = <p>«em class="warning">The function incorrectly accepts some
invalid addresses.</em></p>’;
}
} else {
conclusion = <p>«strong class="fail">The function incorrectly rejects some valid
addresses.</strong></p>';
}
document.getElemenrById('cestResults').innerHTML = conclusion + results.toString));
}
function StrinqBuffer)) {
this.buffer = "";
}
188
Лучшие практики
StringBuffer.prototype.append = functionfstnng) {
this.buffer += string;
return this.
};
StringBuffer.prototype.toString = function() {
return this .buffer;
};
validEmail.css
css
Copy
body {
background-color #fff;
color: #000
}
table {
margin-bottom: 2em
}
caption {
margin-top: 2em
}
good {
background-color. #0f0;
color- #000
}
.warning {
background-color- #fc9;
color #000
}
.fail {
background-color #f00;
color: #fff
}
validEmail.html
<'DOCTYPE html>
<html lang= en'>
<head>
<title>Valid email test</title>
<link rel="stylesheet" href="validEmail.css">
«script src='validEmail.js">«/script>
</head>
«body onload="checkSamples() >
<h1>Unit test for email address validation tunctions«/h1>
<h2>Interactive test</h2>
«form action="#'>
<fieldset>
<legend>Email address«/legend>
use strict
189
<label fur="emailAddress"*Email</label>
<input type='text size="40 value="' name- email' id="emaiiAddress">
<input type= button1' name=-"validate" value- Check address"
onclick="testIsValidEmail(this form.email value) >
</fieldset>
</form>
<n2>Selected samples</h2>
<p>This section shows the results of testing the function with sample strings.
The sample includes both valid strings and invalid strings
according to <a href='http://www.faqs.org/rfcs/rfc2822.html">RFC2822</a>.
</p>
<div id="testResults' >You need to enable JavaScript for this unit test to work,</
div>
</tody>
</html>
use strict
Многие программисты на JavaScript рекомендуют включать строгий режим
ECMAScript 5. добавляя «точную» инструкцию "use strict"; перед любыми други-
ми выражениями:
"use strict";
function ..
Для дальнейшего чтения
Лучшие практики JavaScript:
Coding Cookbook/Validate Email Address
(https://en.wikibooks.org/wiki/JavaScript/Coding_Cuokbook/Validate_
Email_ Address)
«Six JavaScript features we do not need any longer» Christian
Hellmann
(http://wait-iill-i.com/index.php?p=104)
Исходный код рекомендованных Apple функций валидации
JavaScript: checkEmadO и др.
(http:7developer.apple.com/internet/webcontent/validation.html)
190
Лучшие практики
JavaScript form validation — doing it right
(hup://www.xs4all.nl/~sbpoley/wcbmatters/formval.html)
«FORM submission and the ENTER key?»
frttp://ppewww.physics.gla.ac.uk/~flavell/www/formquestion.html)
обсуждает формы, которые отправляются при нажатии Enter;
формы, которые не отправляются при нажатии Enter; и как сде-
лать форму, работающую иначе.
«JavaScript Best Practices» by Matt Kruse
(http://www.mattkruse.com/javascript/bestpractices/)
«Comparing E-mail Address Validating Regular Expressions» содер-
жит список допустимых и недопустимых email-адресов и различ-
ные регулярные выражения, а также их эффективность на этом
списке
(http://fightmgforalosicause.ner/misc/2006/compare-email-regex.php)
Ссылки
1. Jan Wolter. «JavaScript Madness: Query String Parsing» 2011
(http://unixpapa.com/js/querystring.html)
2. PHP bug #39078: Plus sign in URL arg received as space
(https://bugs.php.net/bug.php?id=39078)
ЕДЕ
Ссылки
191
3. Nicholas С. Zakas, «It’s time to start using JavaScript strict mode» 2012
(http://www.nczonline.net/blog/2012/03/13/its-time-to-srart-using-
javascript-strict-mode/)
4. «What does “use strict” do in JavaScript, and what is the reasoning
behind it?»
(http://stackoverilow.com/questions/1335851/what-does-use-sirict-do-
in-javascript-and-what-is-the-reasoning-behind-it)
5. Mozilla Developer Network: “Strict mode”
(htt ps://developer .m uzilla .org/en-US/d ocs/W eb/J avaScri pt/Reference/
runctions_and_function_scope/Strict_mode)
16+
Справочное издание
Анык,тама/1ык, басылым
Серия «!Т для начинающих и опытных»
Юбер Боссо (JackPotte)
JAVASCRIPT. ТОЛЬКО САМОЕ НУЖНОЕ
ОСВАИВАЕМ САМЫЙ ПОПУЛЯРНЫЙ
ЯЗЫК ПРОГРАММИРОВАНИЯ
Ответственный за выпуск: И. В. Резько
Оформление обложки: А Н. Забора
Ответственный редактор. А В. Родионова
Подписано в печать
Формат 70x1007 6. Бумага офсетная. Печать офсетная.
Гарнитура Noto Serif SemiCondensed.
Усл. печ. л. 15,6. Тираж 2000 экз. Заказ N°
Общероссийский классификатор продукции ОК-034-2014 (КПЕС 2008);
58.11.1 — КНИ1И, брошюры печатные.
Изготовлено в 2025 г.
Произведено в Российской Федерации
Изготовитель: ООО «Издательство АСТ».
129085, Российская Федерация, г. Москва, Звездный бульвар, дом 21,
строение 1, комната 705, пом. I, 7 этаж.
Адрес места осуществления деятельности по изготовлению продукции.
123112, Российская Федерация, г. Москва. Пресненская набережная, д. 6, стр. 2,
Деловой комплекс «Империя», 14, 15 этаж.
Наш электронный адрес: ask@ast.ru
Наш сайт: vwvw.ast.ru Интеонет-магазин: www.book24.ru
Онд1рушГ «Издательство АСТ» ЖШК,.
129085, Ресей Федерациясы, Москеу, Звездный бульвары, 21-уй,
1-к.урылыс, 705-белме, I уй-жай, 7-к.абат.
Shim енд!ру к,ызмет1Н жузеге асыру мекенжайьг
123112, Ресей Федерациясы, Мэскеу, Пресненская жат , 6-уй, 2-к,ур.,
«Империя» 1скерл1к кешен!, 14, 15-кабат.
Б1зд!н электрондык, мекенжайымыз: www.ast.ru E-mail: ask@ast.ru
Интернет-магазин, www.book24.kz Интернет-дукен: www.bcok24.kz
Импоотер в Республику Казахстан и Представитель по приему претензий
в Республике Казахстан — ТОО РДЦ Алматы, г Алматы
К,азак,стан Республикасына импорттаушы жене К,азак,стан Республикасында
наразылык,тарды к,абылдау бойынша ект — «РДЦ-Алматы» ЖШС,
Алматы к,., Домбровский кеш., 3«а», Ь литер! офис 1.
Тел.. 8(727) 2 51 59 90.91, факс: 8 (727) 251 59 92 iLUKi 107;
E-mail- RDC-Almaty@eksmo.kz, www book24.kz
Тауар белпа: «АСТ». Онд!р1лген жылы: 2025.
(Эымжц жарамдылык, мерз!М1 шектелмеген.
Ресей Федерациясында енд!р1лген.
JavaScript без лишней «воды» — учитесь быстрее, пишите лучше!
В книге вся информация представлена в концентрированном виде:
минимум абстрактных рассуждений, максимум полезного. Вы полу-
чите четкую теорию, подкрепленную практическими примерами,
и научитесь применять эти знания в реальных проектах.
Почему эта книга — must-have?
• Оптимальный баланс — только необходимая теория + рабо-
чие примеры.
• От основ до продвинутых тем — переменные, функции, DOM,
асинхронность, ООП, модули.
• Актуальный JavaScript — современный синтаксис (ES6+)
и проверенные подходы.
• Для любого уровня — новички получат базу, опытные разра-
ботчики систематизируют знания.
• Четкая структура — учите быстро, находите ответы момен-
тально.
Кому адресована книга?
• Новичкам — чтобы понять JS без лишних сложностей.
• Практикующим разработчикам — чтобы закрыть пробелы
и обновить знания.
• Тем, кто ценит свое время — когда нужен максимум пользы
без тысяч страниц.
Хватит «тонуть» в громоздких учебниках — используйте книгу, кото-
рая учит максимально эффективно!
Смотрите
другие книги
серии
i
X
о
2
5'
*;
я
Kotli'
Основы прог, «
ЯоЛО (/)
Ил—
Python
Системный анализ данных,
расчеты и моделирование
книги ДЛЯ ЛЮБОГО
НАСТРОЕНИЯ ЗДЕСЬ:
www ast.ru / www book24.ru
□ vk.com/izdateistvoast
О ok.ru/izdateistvoast
ACLT
ИЗДАТЕЛЬСКАЯ
ГРУППА ACT
ISBN 978-5-17-174756-5
9 785171 747565 >