1
Введение в JavaScript
Что такое JavaScript
Последнее обновление: 1.11.2015
Сегодняшний мир веб-сайтов трудно представить без языка JavaScript.
JavaScript - это то, что делает живыми веб-страницы, которые мы каждый
день просматриваем в своем веб-браузере.
JavaScript был создан в 1995 году в компании Netscape в качестве языка
сценариев в браузере Netscape Navigator 2. Первоначально язык назывался
LiveScript, но на волне популярности в тот момент другого языка Java
LiveScript был переименован в JavaScript. Однако данный момент до сих пор
иногда приводит к некоторой путанице: некоторые начинающие
разработчики считают, что Java и JavaScript чуть ли не один и тот же язык.
Нет, это абсолютно два разных языка, и они связаны только по названию.
Первоначально JavaScript обладал довольно небольшими возможностями.
Его цель состояла лишь в том, чтобы добавить немного поведения на веб-
страницу. Например, обработать нажатие кнопок на веб-странице,
произвести какие-нибудь другие действия, связанные прежде всего с
элементами управления.
Однако развитие веб-среды, появление HTML5 и технологии [Link] открыло
перед JavaScript гораздо большие горизонты. Сейчас JavaScript продолжает
использоваться для создания веб-сайтов, только теперь он предоставляет
гораздо больше возможностей.
Также он применяется как язык серверной стороны. То есть если раньше
JavaScript применялся только на веб-странице, а на стороне сервера нам надо
было использовать такие технологии, как PHP, [Link], Ruby, Java, то
сейчас благодаря [Link] мы можем обрабатывать все запросы к серверу
также с помощью JavaScript.
В последнее время переживает бум сфера мобильной разработки. И
JavaScript опять же не остается в стороне: увеличение мощности устройств и
повсеместное распространение стандарта HTML5 привело к тому, что для
2
создания приложений для смартфонов и планшетов мы также можем
использовать JavaScript.
Более того благодаря выходу нового семейства операционных систем
Windows: Windows 8 / 8.1 / 10 - можно использовать данный язык
программирования для разработки приложений для этих операционных
систем. То есть JavaScript уже перешагнул границы веб-браузера, которые
ему были очерчены при его создании.
И что вообще раньше казалось фантастикой, но сегодня стало реальностью -
javascript может использоваться для набирающего популярность направления
разработки для IoT(Internet of Things или Интернет вещей). То есть JavaScript
можно использовать для программирования самых различных "умных"
устройств, которые взаимодействуют с интернетом.
Таким образом, вы можете встретить применение JavaScript практически
повсюду. Сегодня это действительно один из самых популярных языков
программирования, и его популярность еще будет расти.
С самого начала существовало несколько веб-браузеров (Netscape, Internet
Explorer), которые предоставляли различные реализации языка. И чтобы
свести различные реализации к общему стержню и стандартизировать язык
под руководством организации ECMA был разработан стандарт ECMAScript.
В принципе сами термины JavaScript и ECMAScript являются во многом
взаимозаменяемыми и относятся к одному и тому же языку.
К настоящему времени ECMA было разработано несколько стандартов
языка, которые отражают его развитие. Последним принятым на
сегодняшний день стандартом является ECMAScript 2015 (ES 6). Но надо
сказать, что реализация этого стандарта в распространенных веб-браузерах
очень далека до завершения, и, возможно, на его полное внедрение уйдет
несколько лет. Поэтому в данном руководстве рассматриваются
преимущественно стандарт ES5 и те функциональные возможности, которые
уже доступны во всех популярных браузерах.
JavaScript является интерпретируемым языком. Это значит, что код на языке
JavaScript выполняется с помощью интерпретатора. Интерпретатор получает
инструкции языка JavaScript, которые определены на веб-странице,
выполняет их (или интерпретирует).
Средства разработки
Для разработки на JavaScript нам потребуется текстовый редактор для
написания кода и веб-браузер для его тестирования. В качестве текстового
3
редактора я советую использовать такую программу как Notepad++. Хотя
этот может быть любой другой текстовый редактор.
Также существуют различные среды разработки, которые поддерживают
JavaScript и облегчают разработку на этом языке, например, Visual Studio,
WebStorm, Netbeans и так далее. При желании можно использовать также эти
среды разработки.
Итак, приступим к созданию первой программы.
Первая программа на JavaScript
Последнее обновление: 1.11.2015
Создадим первую программу на javascript. Для начала определим для нашего
приложения какой-нибудь каталог. Например, назовем его app. В этой папке
создадим файл под названием [Link]. То есть данный файл будет
представлять веб-страницу.
Откроем этот файл в текстовом редакторе, например, в Notepad++, и
определим в файле следующий код:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <h2>Первая программа на JavaScript</h2>
9 <script>
10 alert('Привет мир!');
11 </script>
12 </body>
13 </html>
Здесь мы определяем стандартные элементы html. В
элементе head определяется кодировка utf-8 и заголовок (элемент title). В
4
элементе body определяется тело веб-страницы, состоящее из заголовочного
элемента <h2> и элемента <script>
Подключение кода javascript на html-страницу осуществляется с помощью
тега <script>. Данный тег следует размещать либо в заголовке (между
тегами <head> и </head>), либо в теле веб-странице (между
тегами <body> и </body>). Нередко подключение скриптов происходит перед
закрывающим тегом </body> для оптимизации загрузки веб-страницы.
Раньше надо было в теге <script> указывать тип скрипта, так как данный тег
может использоваться не только для подключения инструкций javascript, но и
для других целей. Так, даже сейчас вы можете встретить на некоторых веб-
страницах такое определение элемента script:
1 <script type="text/javascript">
Но в настоящее время предпочтительнее опускать атрибут type, так как
браузеры по умолчанию считают, что элемент script содержит инструкции
javascript.
Используемый нами код javascript содержит одно выражение:
1 alert('Привет мир!');
Код javascript может содержать множество инструкций и каждая инструкция
завершается точкой с запятой. Наша инструкция вызывает метод alert(),
который отображает сообщение со строкой 'Привет мир!'.
При работе в текстовом редакторе и использовании кириллических символов
нам надо учитывать кодировку. На нашей веб-странице мы использовали
кодировку utf-8. И также надо задать эту кодировку для веб-страницы и в
текстовом редакторе:
В меню кодировок нам надо выбрать пункт "Преобразовать в UTF-8 без
BOM". Далее мы будем использовать кодировку utf-8, поэтому желательно
сразу устанавливать кодировку в текстовом редакторе.
Теперь, когда веб-страница готова, откроем ее в веб-браузере:
И веб-браузер отобразит сообщение, которые мы передали в метод alert в
коде javascript.
5
Выполнение кода javascript
Последнее обновление: 1.11.2015
Когда браузер получает веб-страницу с кодом html и javascript, то он ее
интерпретирует. Результат интерпретации в виде различных элементов -
кнопок, полей ввода, текстовых блоков и т.д., мы видим перед собой в
браузере. Интерпретация веб-страницы происходит последовательно сверху
вниз.
Когда браузер встречает на веб-странице элемент <script> с кодом javascript,
то вступает в действие встроенный интерпретатор javascript. И пока он не
закончит свою работу, дальше интерпретация веб-страницы не идет.
Рассмотрим небольшой пример и для этого изменим страницу [Link] из
прошлой темы следующим образом:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 <script>
7 alert("Секция head");
8 </script>
9 </head>
10 <body>
11 <h2>Первый заголовок</h2>
12 <script>
6
13 alert("Первый заголовок");
14 </script>
15 <h2>Второй заголовок</h2>
16 <script>
17 alert("Второй заголовок");
18 </script>
19 </body>
20 </html>
Здесь три вставки кода javascript - один в секции <head> и по одному после
каждого заголовка.
Откроем веб-страницу в браузере:
Несмотря на то, что на нашей веб-странице объявлено два заголовка, но в
браузере их еще не видно, поскольку выполняется код javascript из секции
head. И пока мы не закроем окно сообщения, дальше интерпретация веб-
станицы идти не будет.
После закрытия окна с сообщением браузер добавит на страницу первый
заголовок и снова остановится на следующем блоке кода javascript:
После закрытия окна сообщения браузер двинется дальше и добавит на
страницу второй заголовок и остановится на третьем блоке кода javascript:
После закрытия третьего окна с сообщением браузер закончит
интерпретацию веб-страницы, и веб-страница окажется полностью
загружена. Данный момент очень важен, поскольку может влиять на
производительность. Поэтому нередко вставки кода javascript идут перед
закрывающим тегом </body>, когда основная часть веб-страницы уже
загружена в браузере.
То есть в нашем случае мы могли бы перенести все вставки кода javascript
вниз:
7
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <h2>Первый заголовок</h2>
9 <h2>Второй заголовок</h2>
10 <script>
11 alert("Секция head");
12 alert("Первый заголовок");
13 alert("Второй заголовок");
14 </script>
15 </body>
16 </html>
Основы синтаксиса javascript
Прежде чем переходить к детальному изучению основ языка
программирования javascript, рассмотрим некоторые базовые моменты его
синтаксиса.
Код javascript состоит из инструкций, каждая из которых завершается точкой
запятой:
1 alert("Вычисление выражения"); var a = 5 + 8; alert(a);
Однако современные браузеры вполне могут различать отдельные
инструкции, если они просто располагаются на отдельных строках без точки
запятой:
1 alert("Вычисление выражения")
2 var a = 5 + 8
3 alert(a)
8
Но чтобы улучшить читабельность кода и снизить число возможных ошибок,
рекомендуется определять каждую инструкцию javascript на отдельной
строчке и завершать ее точкой с запятой, как в первом варианте.
В коде javascript могут использоваться комментарии. Комментарии не
обрабатываются интерпретатором javascript и никак не учитываются в работе
программы. Они предназначен для ориентации по коду, чтобы указать, что
делает тот или иной код.
Комментарии могут быть однострочными, для которых используется
двойной слеш:
1 // вывод сообщения
2 alert("Вычисление выражения");
3 // арифметическая операция
4 var a = 5 + 8;
5 alert(a);
Кроме однострочных комментариев могут использоваться и многострочные.
Такие комментарии заключаются между символами /*текст комментария*/.
Например:
1 /* вывод сообщения и
2 арифметическая операция */
3 alert("Вычисление выражения");
4 var a = 5 + 8;
5 alert(a);
Подключение внешнего файла JavaScript
Последнее обновление: 1.11.2015
Еще один способ подключения кода JavaScript на веб-страницу представляет
вынесение кода во внешние файлы и их подключение с помощью тега <script>
9
Итак, в прошлой теме мы создали html-страницу [Link], которая находится в
каталоге app. Теперь создадим в этом каталоге новый подкаталог. Назовем его js. Он
будет предназначен для хранения файлов с кодом javascript. В этом подкаталоге
создадим новый текстовый файл, который назовем [Link]. Файлы с кодом
javascript имеют расширение .js. То есть у нас получится следующая структура в
папке app:
Откроем файл [Link] в текстовом редакторе и определим в нем следующий код:
1 var date = new Date(); // получаем текущую дату
2 var time = [Link](); // получаем текущее время в часах
3 if(time < 13) // сравниваем время с число 13
4 alert('Доброе утро!'); // если время меньше 13
5 else
6 alert('Добрый вечер!'); // если время равно 13 и больше
Для совместимости с кодировкой страницы [Link] для файла с кодом javascript
также желательно устанавливать кодировку utf-8.
Здесь уже больше выражений языка javascript. Первое выражение получает текущую
дату и присваивает ее переменной date. С помощью второй инструкции получаем
время в часах. Дальше мы сравниваем полученное время с числом 13 и в зависимости
от результатов проверки выводим первое или второе сообщение.
Теперь подключим этот файл на веб-страницу [Link]:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <h2>Первая программа на JavaScript</h2>
9 <script src="js/[Link]"></script>
10 </body>
11 </html>
Чтобы подключить файл с кодом javascript на веб-страницу, применяется также
тег <script>, у которого устанавливается атрибут src. Этот атрибут указывает на
путь к файлу скрипта. В нашем случае используется относительный путь. Так как веб-
страница находится в одной папке с каталогом js, то в качестве пути мы можем
написать js/[Link].
10
Также надо учитывать, что за открывающим тегом script должен обязательно
следовать закрывающий </script>
И после открытия файла [Link] в браузере отобразится сообщение:
В отличие от определения кода javascript вынесение его во внешние файлы имеет ряд
преимуществ:
Мы можем повторно использовать один и тот же код на нескольких веб-
страницах
Внешние файлы javascript бразуер может кэшировать, за счет этого при
следующем обращении к странице браузер снижает нагрузка на сервер, а
браузеру надо загрузить меньший объем информации
Код веб-страницы становится "чище". Он содержит только html-разметку, а код
поведения хранится во внешних файлах. В итоге можно отделить работу по
созданию кода html-страницы от написания кода javascript
Поэтому, как правило, предпочтительнее использовать код javascript во внешних
файлах, а не в прямых вставках на веб-страницу с помощью элемента script.
НазадСодержаниеВперед
Консоль браузера, [Link] и
[Link]
Последнее обновление: 1.11.2015
Незаменимым инструментом при работе с JavaScript является консоль браузера,
которая позволяет производить отладку программы. Во многих современных
браузерах есть подобная консоль. Например, чтобы открыть консоль в Google Chrome,
нам надо перейти в меню Дополнительные инструменты -> Консоль JavaScript:
После этого внизу браузера откроется консоль:
11
Мы можем напрямую вводить в консоль браузера выражения JavaScript, и они будут
выполняться. Например, введем в консоли следующий текст:
1 alert("Привет мир");
Браузер выполнит данную команду и отобразит нам окно с сообщением.
Для вывода различного рода информации в консоли браузера используется
специальная функция [Link](). Например, определим следующую веб-страницу:
1
<!DOCTYPE html>
2
<html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <h2>Первая программа на JavaScript</h2>
9 <script>
10 var a = 5 + 8;
[Link]("Результат операции");
11
[Link](a);
12
</script>
13
</body>
14
</html>
15
В коде javascript с помощью ключевого слова var объявляется переменная a, которой
присваивается сумма двух чисел 5 и 8: var a = 5 + 8. С помощью
метода [Link]() выводится значение переменной a. И после запуска веб-
страницы в браузере мы увидим в консоли результат выполнения кода:
12
В дальнейшем мы часто будем обращаться к консоли и использовать функцию
[Link].
Метод [Link]
Также на начальном этапе нам может быть полезен метод [Link](),
который пишет информацию на веб-страницу.
Например, возьмем предыдущий пример и изменим в нем метод [Link] на
[Link]:
1
<!DOCTYPE html>
2
<html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <h2>Первая программа на JavaScript</h2>
9 <script>
10 var a = 5 + 8;
[Link]("Результат операции ");
11
[Link](a);
12
</script>
13
</body>
14
</html>
15
Программа выводит результат операции напрямую на веб-страницу:
Основы javascript
Переменные и константы
Последнее обновление: 05.04.2018
13
Для хранения данных в программе используются переменные. Переменные
предназначены для хранения каких-нибудь временных данных или таких данных,
которые в процессе работы могут менять свое значение. Для создания переменных
применяются ключевые слова var и let. Например, объявим переменную myIncome:
1 var myIncome;
2 // другой вариант
3 let myIncome2;
Каждая переменная имеет имя. Имя представляет собой произвольный набор
алфавитно-цифровых символов, знака подчеркивания (_) или знака доллара ($),
причем названия не должны начинаться с цифровых символов. То есть мы можем
использовать в названии буквы, цифры, подчеркивание. Однако все остальные
символы запрещены.
Например, правильные названия переменных:
1 $commision
2 someVariable
3 product_Store
4 income2
5 myIncome_from_deposit
Следующие названия являются некорректными и не могут использоваться:
1 222lol
2 @someVariable
3 my%percent
Также нельзя давать переменным такие имена, которые совпадают с
зарезервированными ключевыми словами. В JavaScript не так много ключевых слов,
поэтому данное правило не сложно соблюдать. Например, следующее название будет
некорректным, так как for - ключевое слово в JavaScript:
1 var for;
14
Список зарезервированных слов в JavaScript:
abstract, boolean, break, byte, case, catch, char, class, const, continue, debugger, default,
delete, do, double, else, enum, export, extends, false, final, finally, float, for, function, goto,
if, implements, import, in, instanceof, int, inteface, long, native, new, null, package, private,
protected, public, return, short, static, super, switch, synchronized, this, throw, throws,
transient, true, try, typeof, var, volatile, void, while, with
При названии переменных надо учитывать, что JavaScript
является регистрозависимым языком, то есть в следующем коде объявлены две
разные переменные:
1 var myIncome;
2 var MyIncome;
Через запятую можно определить сразу несколько переменных:
1 var myIncome, procent, sum;
2 let a, b, c;
С помощью знака равно (который еще называют оператором присваивания) можно
присвоить переменной какое-либо значение:
1 var income = 300;
2 let price = 76;
Процесс присвоения переменной начального значения называется инициализацией.
Теперь переменная income будет хранить число 300, а переменная price - число 76.
Отличительной чертой переменных является то, что мы можем изменить их значение:
1 var income = 300;
2 income = 400;
3 [Link](income);
4
5 let price = 76;
6 price = 54;
7 [Link](price);
15
Константы
С помощью ключевого слова const можно определить константу, которая, как и
переменная, хранит значение, однако это значение не может быть изменено.
1 const rate = 10;
Если мы попробуем изменить ее значение, то мы столкнемся с ошибкой:
const rate = 10;
1
rate = 23; // ошибка, rate - константа, поэтому мы не можем изменить ее
2 значение
Также стоит отметить, что поскольку мы не можем изменить значение константы, то
она должна быть инициализирована, то есть при ее определении мы должны
предоставить ей начальное значение. Если мы этого не сделаем, то опять же мы
столкнемся с ошибкой:
1 const rate; // ошибка, rate не инициализирована
Типы данных
Последнее обновление: 26.03.2018
Все используемые данные в javascript имеют определенный тип. В JavaScript имеется
пять примитивных типов данных:
String: представляет строку
Number: представляет числовое значение
Boolean: представляет логическое значение true или false
undefined: указывает, что значение не установлено
null: указывает на неопределенное значение
16
Все данные, которые не попадают под вышеперечисленные пять типов, относятся к
типу object
Числовые данные
Числа в JavaScript могут иметь две формы:
Целые числа, например, 35. Мы можем использовать как положительные, так и
отрицательные числа. Диапазон используемых чисел: от -2 53 до 253
Дробные числа (числа с плавающей точкой), например, 3.5575. Опять же можно
использовать как положительные, так и отрицательные числа. Для чисел с
плавающей точкой используется тот же диапазон: от -2 53 до 253
Например:
1 var x = 45;
2 var y = 23.897;
В качестве разделителя между целой и дробной частями, как и в других языках
программирования, используется точка.
Строки
Тип string представляет строки, то есть такие данные, которые заключены в
кавычки. Например, "Привет мир". Причем мы можем использовать как двойные, так и
одинарные кавычки: "Привет мир" и 'Привет мир'. Единственно ограничение: тип
закрывающей кавычки должен быть тот же, что и тип открывающей, то есть либо обе
двойные, либо обе одинарные.
Если внутри строки встречаются кавычки, то мы их должны экранировать слешем.
Например, пусть у нас есть текст "Бюро "Рога и копыта"". Теперь экранируем
кавычки:
1 var companyName = "Бюро \"Рога и копыта\"";
Также мы можем внутри стоки использовать другой тип кавычек:
1 var companyName1 = "Бюро 'Рога и копыта'";
2 var companyName2 = 'Бюро "Рога и копыта"';
Тип Boolean
Тип Boolean представляет булевые или логические значения true и false (то есть да
или нет):
17
1 var isAlive = true;
2 var isDead = false;
null и undefined
Нередко возникает путаница между null и undefined. Итак, когда мы только
определяем переменную без присвоения ей начального значения, она представляет
тип undefined:
1 var isAlive;
2 [Link](isAlive); // выведет undefined
Присвоение значение null означает, что переменная имеет некоторое неопределенное
значение (не число, не строка, не логическое значение), но все-таки имеет значение
(undefined означает, что переменная не имеет значения):
1 var isAlive;
2 [Link](isAlive); // undefined
3 isAlive = null;
4 [Link](isAlive); // null
5 isAlive = undefined; // снова установим тип undefined
6 [Link](isAlive); // undefined
object
Тип object представляет сложный объект. Простейшее определение объекта
представляют фигурные скобки:
1 var user = {};
Объект может иметь различные свойства и методы:
1 var user = {name: "Tom", age:24};
2 [Link]([Link]);
В данном случае объект называется user, и он имеет два свойства: name и age. Это
краткое описание объектов, более подробное описание приводится в
соответствующей главе.
18
Слабая типизация
JavaScript является языком со слабой типизацией. Это значит, что переменные могут
динамически менять тип. Например:
1 var xNumber; // тип undefined
2 [Link](xNumber);
3 xNumber = 45; // тип number
4 [Link](xNumber);
5 xNumber = "45"; // тип string
6 [Link](xNumber);
Несмотря на то, что во втором и третьем случае консоль выведет нам число 45, но во
втором случае переменная xNumber будет представлять число, а в третьем случае -
строку.
Это важный момент, который надо учитывать и от которого зависит поведение
переменной в программе:
1 var xNumber = 45; // тип number
2 var yNumber = xNumber + 5;
3 [Link](yNumber); // 50
4
5 xNumber = "45"; // тип string
6 var zNumber = xNumber + 5
7 [Link](zNumber); // 455
Выше в обоих случая к переменной xNumber применяется операция сложения (+). Но
в первом случае xNumber представляет число, поэтому результатом операции xNumber
+ 5 будет число 50.
Во втором случае xNumber представляет строку. Но операция сложения между
строкой и числом 5 невозможна. Поэтому число 5 будет преобразовываться к строке,
и будет происходить операция объединения строк. И результатом выражения xNumber
+ 5 будет стока "455".
Оператор typeof
С помощью оператора typeof можно получить тип переменной:
19
1 var name = "Tom";
2 [Link](typeof name); // string
3
4 var income = 45.8;
5 [Link](typeof income); // number
6
7 var isEnabled = true;
8 [Link](typeof isEnabled); // boolean
9
10 var undefVariable;
[Link](typeof undefVariable); // undefined
11
Операции с переменными
Последнее обновление: 1.11.2015
Математические операции
JavaScript поддерживает все базовые математические операции:
Сложение:
1 var x = 10;
2 var y = x + 50;
Вычитание:
1 var x = 100;
2 var y = x - 50;
Умножение:
20
1 var x = 4;
2 var y = 5;
3 var z = x * y;
Деление:
1 var x = 40;
2 var y = 5;
3 var z = x / y;
Деление по модулю (оператор %) возвращает остаток от деления:
1 var x = 40;
2 var y = 7;
3 var z = x % y;
4 [Link](z); // 5
Результатом будет 5, так как наибольшее целое число, которое меньше или равно 40
и при этом делится на 7 равно 35, а 40 - 35 = 5.
Инкремент:
1 var x = 5;
2 x++; // x = 6
Оператор инкремента ++ увеличивает переменную на единицу. Существует
префиксный инкремент, который сначала увеличивает переменную на единицу, а
затем возвращает ее значение. И есть постфиксный инкремент, который сначала
возвращает значение переменной, а затем увеличивает его на единицу:
1 // префиксный инкремент
2 var x = 5;
3 var z = ++x;
[Link](x); // 6
4
[Link](z); // 6
5
6
// постфиксный инкремент
21
7
var a = 5;
8
var b = a++;
9
[Link](a); // 6
10
[Link](b); // 5
11
Постфиксный инкремент аналогичен операции:
1 a = a + 1; // a++
Декремент уменьшает значение переменной на единицу. Также есть префиксный и
постфиксный декремент:
1 // префиксный декремент
2 var x = 5;
3 var z = --x;
4 [Link](x); // 4
5 [Link](z); // 4
6
7 // постфиксный декремент
8 var a = 5;
9 var b = a--;
[Link](a); // 4
10
[Link](b); // 5
11
Как и принято в математике, все операции выполняются слева направо и различаются
по приоритетам: сначала операции инкремента и декремента, затем выполняются
умножение и деление, а потом сложение и вычитание. Чтобы изменить стандартный
ход выполнения операций, часть выражений можно поместить в скобки:
1 var x = 10;
2 var y = 5 + (6 - 2) * --x;
3 [Link](y); //41
22
Операции присваивания
=
Приравнивает переменной определенное значение: var x = 5;
+=
Сложение с последующим присвоением результата. Например:
1 var a = 23;
2 a += 5; // аналогично a = a + 5
3 [Link](a); // 28
-=
Вычитание с последующим присвоением результата. Например:
1 var a = 28;
2 a -= 10; // аналогично a = a - 10
3 [Link](a); // 18
*=
Умножение с последующим присвоением результата:
1 var x = 20;
2 x *= 2; // аналогично x = x * 2
3 [Link](x); // 40
/=
Деление с последующим присвоением результата:
1 var x = 40;
2 x /= 4; // аналогично x = x / 4
3 [Link](x); // 10
%=
Получение остатка от деления с последующим присвоением результата:
23
1 var x = 10;
2 x %= 3; // аналогично x = x % 3
3 [Link](x); // 1, так как 10 - 3*3 = 1
Операторы сравнения
Как правило, для проверки условия используются операторы сравнения. Операторы
сравнения сравнивают два значения и возвращают значение true или false:
==
Оператор равенства сравнивает два значения, и если они равны, возвращает
true, иначе возвращает false: x == 5
===
Оператор тождественности также сравнивает два значения и их тип, и если
они равны, возвращает true, иначе возвращает false: x === 5
!=
Сравнивает два значения, и если они не равны, возвращает true, иначе
возвращает false: x != 5
!==
Сравнивает два значения и их типы, и если они не равны, возвращает true,
иначе возвращает false: x !== 5
>
Сравнивает два значения, и если первое больше второго, то возвращает true,
иначе возвращает false: x > 5
<
Сравнивает два значения, и если первое меньше второго, то возвращает true,
иначе возвращает false: x < 5
>=
Сравнивает два значения, и если первое больше или равно второму, то
возвращает true, иначе возвращает false: x >= 5
<=
Сравнивает два значения, и если первое меньше или равно второму, то
возвращает true, иначе возвращает false: x <= 5
24
Все операторы довольно просты, наверное, за исключением оператора равенства и
оператора тождественности. Они оба сравнивают два значения, но оператор
тождественности также принимает во внимание и тип значения. Например:
1 var income = 100;
2 var strIncome = "100";
3 var result = income == strIncome;
4 [Link](result); //true
Переменная result здесь будет равна true, так как фактически и income, и strIncome
представляют число 100.
Но оператор тождественности возвратит в этом случае false, так как данные имеют
разные тип:
1 var income = 100;
2 var strIncome = "100";
3 var result = income === strIncome;
4 [Link](result); // false
Аналогично работают операторы неравенства != и !==.
Логические операции
Логические операции применяются для объединения результатов двух операций
сравнения. В JavaScript есть следующие логические операции:
&&
Возвращает true, если обе операции сравнения возвращают true, иначе
возвращает false:
1 var income = 100;
2 var percent = 10;
3 var result = income > 50 && percent < 12;
4 [Link](result); //true
||
25
Возвращает true, если хотя бы одна операция сравнения возвращают true,
иначе возвращает false:
1 var income = 100;
2 var isDeposit = true;
3 var result = income > 50 || isDeposit == true;
4 [Link](result); //true
!
Возвращает true, если операция сравнения возвращает false:
1 var income = 100;
2 var result1 = !(income > 50);
3 [Link](result1); // false, так как income > 50 возвращает true
4
5 var isDeposit = false;
6 var result2 = !isDeposit;
7 [Link](result2); // true
Операции со строками
Строки могут использовать оператор + для объединения. Например:
1 var name = "Том";
2 var surname = "Сойер"
3 var fullname = name + " " + surname;
4 [Link](fullname); //Том Сойер
Если одно из выражений представляет строку, а другое - число, то число
преобразуется к строке и выполняется операция объединения строк:
1 var name = "Том";
2 var fullname = name + 256;
3 [Link](fullname); //Том256
26
В конце напишем небольшую программу, которая продемонстрирует работу с
операциями над переменными. Для этого определим следующую веб-страницу
[Link]:
1
<!DOCTYPE html>
2
<html>
3
<head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <script>
9 var sum = 500; // сумма вклада
10 var percent = 10; // процент по вкладу
11 var income = sum * percent / 100; // доход по вкладу
sum = sum + income; // определяем новую сумму
12
[Link]("Доход по вкладу: " + income);
13
[Link]("Сумма вклада после первого года: " + sum);
14
</script>
15
</body>
16
</html>
17
В скрипте объявляются три переменных: sum, percent и income. Переменная income
вычисляется по остальным двум переменным с помощью операций умножения и
деления. И в конце ее значение суммируется с значением переменной sum.
И консоль браузера выведет:
Преобразования данных
Последнее обновление: 1.11.2015
27
Нередко возникает необходимость преобразовать одни данные в другие. Например:
1 var number1 = "46";
2 var number2 = "4";
3 var result = number1 + number2;
4 [Link](result); //464
Обе переменных представляют строки, а точнее строковые представления чисел. И в
итоге мы получим не число 50, а строку 464. Но было бы неплохо, если бы их тоже
можно было бы складывать, вычитать, в общем работать как с обычными числами.
В этом случае мы можем использовать операции преобразования. Для преобразования
строки в число применяется функция parseInt():
1 var number1 = "46";
2 var number2 = "4";
3 var result = parseInt(number1) + parseInt(number2);
4 [Link](result); // 50
Для преобразования строк в дробные числа применяется функция parseFloat():
1 var number1 = "46.07";
2 var number2 = "4.98";
3 var result = parseFloat(number1) + parseFloat(number2);
4 [Link](result); //51.05
При этом строка может иметь смешанное содержимое, например, "123hello", то есть в
данном случае есть цифры, но есть и обычные символы. Но метод parseInt() все
равно попытается выполнить преобразование:
1 var num1 = "123hello";
2 var num2 = parseInt(num1);
3 [Link](num2); // 123
Если методу не удастся выполнить преобразование, то он возвращает
значение NaN (Not a Number), которое говорит о том, что строка не представляет
число и не может быть преобразована.
С помощью специальной функции isNaN() можно проверить, представляет ли строка
число. Если строка не является числом, то функция возвращает true, если это число -
то false:
1 var num1 = "javascript";
2 var num2 = "22";
3 var result = isNaN(num1);
4 [Link](result); // true - num1 не является числом
5
6 result = isNaN(num2);
28
7 [Link](result); // false - num2 - это число
Выше мы рассматривали перевод строк в числа в десятичной системе. Однако мы
можем переводить числа в любую систему. По умолчанию интерпретатор JavaScript
сам отгадывает, в число из какой системы исчисления мы хотим преобразовать строку
(как правило, выбирается десятичная система). Но мы можем с помощью второго
параметра явно указать, что хотим преобразовать строку в число в определенной
системе. Например, преобразование в число в двоичной системе:
1 var num1 = "110";
2 var num2 = parseInt(num1, 2);
3 [Link](num2); // 6
Результатом будет 6, так как 110 в двоичной системе - это число 6 в десятичной.
Теперь напишем небольшую программу, в которой используем операции с
переменными:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title>JavaScript</title>
6 </head>
7 <body>
8 <script>
9 var strSum = prompt("Введите сумму вклада", 1000);
10 var strPercent = prompt("Введите процентную ставку", 10);
11 var sum = parseInt(strSum);
12 var procent = parseInt(strPercent);
13 sum = sum + sum * procent / 100;
14 alert("После начисления процентов сумма вклада составит: " + sum);
15 </script>
16 </body>
17 </html>
С помощью функции prompt() в браузере выводится диалоговое окно с
предложением ввести некоторое значение. Второй аргумент в этой функции
указывает на значение, которое будет использоваться по умолчанию.
Однако функция prompt() возвращает строку. Поэтому эту строку нам надо
преобразовать в число, чтобы выполнить с ней операции.
После открытия страницы в браузере мы увидим приглашение к вводу суммы вклада:
29
Затем подобное сообщение отобразится и для ввода процента. И в конце программа
получит данные, преобразует их в числа и выполнит подсчет:
НазадСодержаниеВперед
Массивы
Последнее обновление: 09.04.2018
Для работы с наборами данных предназначены массивы. Для создания массива
применяется выражение new Array():
1 var myArray = new Array();
Существует также более короткий способ инициализации массива:
1 var myArray = [];
В данном случае мы создаем пустой массив. Но можно также добавить в него
начальные данные:
1 var people = ["Tom", "Alice", "Sam"];
2 [Link](people);
В этом случае в массиве myArray будет три элемента. Графически его можно
представить так:
Индекс Элемент
0 Tom
1 Alice
2 Sam
30
Для обращения к отдельным элементам массива используются индексы. Отсчет
начинается с нуля, то есть первый элемент будет иметь индекс 0, а последний - 2:
1 var people = ["Tom", "Alice", "Sam"];
2 [Link](people[0]); // Tom
3 var person3 = people[2]; // Sam
4 [Link](person3); // Sam
Если мы попробуем обратиться к элементу по индексу больше размера массива, то мы
получим undefined:
1 var people = ["Tom", "Alice", "Sam"];
2 [Link](people[7]); // undefined
Также по индексу осуществляется установка значений для элементов массива:
1 var people = ["Tom", "Alice", "Sam"];
2 [Link](people[0]); // Tom
3 people[0] = "Bob";
4 [Link](people[0]); // Bob
Причем в отличие от других языков, как C# или Java, можно установить элемент,
который изначально не установлен:
1 var people = ["Tom", "Alice", "Sam"];
2 [Link](people[7]); // undefined - в массиве только три элемента
3 people[7] = "Bob";
4 [Link](people[7]); // Bob
Также стоит отметить, что в отличие от ряда языков программирования в JavaScript
массивы не являются строго типизированными, один массив может хранить данные
разных типов:
1 var objects = ["Tom", 12, true, 3.14, false];
2 [Link](objects);
spread-оператор
spread-оператор ... позволяет взять значения из массива по отдельности:
31
1 let numbers = [1, 2, 3, 4];
2 [Link](...numbers); // 1 2 3 4
3 [Link](numbers); // [1, 2, 3, 4]
spread-оператор указывается перед массивом. В результате
выражение ...numbers возвратит набор чисел, но это будет не массив, а именно
отедльные значения.
Многомерные массивы
Массивы могут быть одномерными и многомерными. Каждый элемент в многомерном
массиве может представлять собой отдельный массив. Выше мы рассматривали
одномерный массив, теперь создадим многомерный массив:
1 var numbers1 = [0, 1, 2, 3, 4, 5 ]; // одномерный массив
2 var numbers2 = [[0, 1, 2], [3, 4, 5] ]; // двумерный массив
Визуально оба массива можно представить следующим образом:
Одномерный массив numbers1
0 1 2 3 4 5
Двухмерный массив numbers2
0 1 2
3 4 5
Поскольку массив numbers2 двухмерный, он представляет собой простую таблицу.
Каждый его элемент может представлять отдельный массив.
Рассмотрим еще один двумерный массив:
1 var people = [
2 ["Tom", 25, false],
3 ["Bill", 38, true],
["Alice", 21, false]
4
];
5
6
[Link](people[0]); // ["Tom", 25, false]
7
[Link](people[1]); // ["Bill", 38, true]
32
Массив people можно представить в виде следующей таблицы:
Tom 25 false
Bill 38 true
Alice 21 false
Чтобы получить отдельный элемент массива, также используется индекс:
1 var tomInfo = people[0];
Только теперь переменная tomInfo будет представлять массив. Чтобы получить
элемент внутри вложенного массива, нам надо использовать его вторую размерность:
1 [Link]("Имя: " + people[0][0]); // Tom
2 [Link]("Возраст: " + people[0][1]); // 25
То есть если визуально двумерный массив мы можем представить в виде таблицы, то
элемент people[0][1] будет ссылаться на ячейку таблицы, которая находится на
пересечении первой строки и второго столбца (первая размерность - 0 - строка,
вторая размерность - 1 - столбец).
Также мы можем выполнить присвоение:
1 var people = [
2 ["Tom", 25, false],
3 ["Bill", 38, true],
4 ["Alice", 21, false]
5 ];
6 people[0][1] = 56; // присваиваем отдельное значение
7 [Link](people[0][1]); // 56
8
people[1] = ["Bob", 29, false]; // присваиваем массив
9
[Link](people[1][0]); // Bob
10
33
При создании многомерных массивов мы не ограничены только двумерными, но также
можем использовать массивы больших размерностей:
1 var numbers = [];
2 numbers[0] = []; // теперь numbers - двумерный массив
3 numbers[0][0]=[]; // теперь numbers - трехмерный массив
4 numbers[0][0][0] = 5; // первый элемент трехмерного массива равен 5
5 [Link](numbers[0][0][0]);
НазадСодержаниеВперед
Условные конструкции
Последнее обновление: 27.07.2016
Условные конструкции позволяют выполнить те или иные действия в зависимости от
определенных условий.
Выражение if
Конструкция if проверяет некоторое условие и если это условие верно, то выполняет
некоторые действия. Общая форма конструкции if:
1 if(условие) действия;
Например:
1 var income = 100;
2 if(income > 50) alert("доход больше 50");
Здесь в конструкции if используется следующее условие: income > 50. Если это
условие возвращает true, то есть переменная income имеет значение больше 50, то
браузер отображает сообщение. Если же значение income меньше 50, то никакого
сообщения не отображается.
34
Если необходимо выполнить по условию набор инструкций, то они помещаются в блок
из фигурных скобок:
1 var income = 100;
2 if(income > 50){
3
4 var message = "доход больше 50";
5 alert(message);
6 }
Причем условия могут быть сложными:
1 var income = 100;
2 var age = 19;
3 if(income < 150 && age > 18){
4
5 var message = "доход больше 50";
6 alert(message);
7 }
Конструкция if позволяет проверить наличие значения. Например:
1 var myVar = 89;
2 if(myVar){
3 // действия
4 }
Если переменная myVar имеет значение, то в условной конструкции она возвратит
значение true.
Но нередко для проверки значения переменной используют альтернативный вариант -
проверяют на значение undefined:
1 if (typeof myVar != "undefined") {
2 // действия
}
35
В конструкции if мы также можем использовать блок else. Данный блок содержит
инструкции, которые выполняются, если условие после if ложно, то есть равно false:
1 var age = 17;
if(age >= 18){
2
3
alert("Вы допущены к программе кредитования");
4
}
5
else{
6
alert("Вы не можете участвовать в программе, так как возраст меньше
7 18");
8 }
С помощью конструкции else if мы можем добавить альтернативное условие к блоку
if:
1 var income = 300;
2 if(income < 200){
3
4 alert("Доход ниже среднего");
5 }
6 else if(income >= 200 && income <= 400){
7
8 alert("Средний доход");
9 }
10 else{
11
alert("Доход выше среднего");
12
}
13
В данном случае выполнится блок else if. При необходимости мы можем использовать
несколько блоков else if с разными условиями:
36
1
if(income < 200){
2
3 alert("Доход ниже среднего");
4 }
5 else if(income>=200 && income<300){
6
7 alert("Чуть ниже среднего");
8 }
9 else if(income>=300 && income<400){
10
11 alert("Средний доход");
12 }
else{
13
alert("Доход выше среднего");
14
}
15
True или false
В javascript любая переменная может применяться в условных выражениях, но не
любая переменная представляет тип boolean. И в этой связи возникает вопрос, что
возвратит та или иная переменная - true или false? Много зависит от типа данных,
который представляет переменная:
undefined
Возвращает false
null
Возвращает false
Boolean
Если переменная равна false, то возвращается false. Соответствено если
переменная равна true, то возвращается true
Number
37
Возвращает false, если число равно 0 или NaN (Not a Number), в остальных
случаях возвращается true
Например, следующая переменная будет возращать false:
1
var x = NaN;
2
if(x){ // false
3
4
}
5
String
Возвращает false, если переменная равна пустой строке, то есть ее длина
равна 0, в остальных случаях возвращается true
1
var y = ""; // false - так как пустая строка
2
var z = "javascript"; // true - строка не пустая
3
Object
Всегда возвращает true
1
var user = {name:"Tom"}; // true
2
var isEnabled = new Boolean(false) // true
3
var car = {} // true
4
Конструкция switch..case
Конструкция switch..case является альтернативой использованию
конструкции if..else if..else и также позволяет обработать сразу несколько
условий:
1 var income = 300;
2 switch(income){
3
4 case 100 :
38
5 [Link]("Доход равен 100");
6 break;
7 case 200 :
8 [Link]("Доход равен 200");
9 break;
10 case 300 :
11 [Link]("Доход равен 300");
break;
12
}
13
После ключевого слова switch в скобках идет сравниваемое выражение. Значение
этого выражения последовательно сравнивается со значениями, помещенными после
оператора сase. И если совпадение будет найдено, то будет выполняться
определенный блок сase.
В конце каждого блока сase ставится оператор break, чтобы избежать выполнения
других блоков.
Если мы хотим также обработать ситуацию, когда совпадения не будет найдено, то
можно добавить блок default:
1 var income = 300;
2 switch(income){
3
4 case 100 :
[Link]("Доход равен 100");
5
break;
6
case 200 :
7
[Link]("Доход равен 200");
8
break;
9
case 300 :
10
[Link]("Доход равен 300");
11
break;
12 default:
13 [Link]("Доход неизвестной величины");
39
14
break;
15
}
16
Тернарная операция
Тернарная операция состоит из трех операндов и имеет следующее
определение: [первый операнд - условие] ? [второй операнд] : [третий операнд].
В зависимости от условия тернарная операция возвращает второй или третий
операнд: если условие равно true, то возвращается второй операнд; если условие
равно false, то третий. Например:
1 var a = 1;
2 var b = 2;
3 var result = a < b ? a + b : a - b;
4 [Link](result); // 3
Если значение переменной a меньше значения переменной b, то переменная result
будет равняться a + b. Иначе значение result будет равняться a - b.
Циклы
Последнее обновление: 08.04.2018
Циклы позволяют в зависимости от определенных условий выполнять некоторое
действие множество раз. В JavaScript имеются следующие виды циклов:
for
for..in
for..of
while
do..while
40
Цикл for
Цикл for имеет следующее формальное определение:
1 for ([инициализация счетчика]; [условие]; [изменение счетчика]){
2
3 // действия
4 }
Например, используем цикл for для перебора элементов массива:
1 var people = ["Tom", "Alice", "Bob", "Sam"];
2 for(var i = 0; i<[Link]; i++){
3
4 [Link](people[i]);
5 }
Первая часть объявления цикла - var i = 0 - создает и инициализирует счетчик -
переменную i. И перед выполнением цикла ее значение будет равно 0. По сути это то
же самое, что и объявление переменной.
Вторая часть - условие, при котором будет выполняться цикл. В данном случае цикл
будет выполняться, пока значение i не достигнет величины, равной длине массива
people. Получить длину массива можно с помощью свойства length: [Link].
Третья часть - приращение счетчика на единицу.
И так как в массиве 4 элемента, то блок цикла сработает 4 раза, пока значение i не
станет равным [Link] (то есть 4). И каждый раз это значение будет
увеличиваться на 1. Каждое отдельное повторение цикла называется итерацией.
Таким образом, в данном случае сработают 4 итерации.
А с помощью выражения people[i] мы сможем получить элемент массива для его
последующего вывода в браузере.
Необязательно увеличивать счетчик на единицу, можно производить с ним другие
действия, например, уменьшать на единицу:
1 var people = ["Tom", "Alice", "Bob", "Sam"];
2 for(var i = [Link] - 1; i >= 0; i--){
41
3
4 [Link](people[i]);
5 }
В данном случае массив выводится с конца, а перебор массива начинается с i = 3 до i
= 0.
for..in
Цикл for..in предназначен для перебора массивов и объектов. Его формальное
определение:
1 for (индекс in массив) {
2 // действия
3 }
Например, переберем элементы массива:
1 var people = ["Tom", "Alice", "Bob", "Sam"];
2 for(var index in people){
3
4 [Link](people[index]);
5 }
Цикл for...of
Цикл for...of похож на цикл for...in и предназначен для перебора коллекций,
например, массивов:
1 let users = ["Tom", "Bob", "Sam"];
2 for(let val of users)
3 [Link](val);
Текущий перебираемый элемент коллекции помещается в переменную val, значение
которой затем выводится на консоль.
Цикл while
Цикл while выполняется до тех пор, пока некоторое условие истинно. Его формальное
определение:
42
1 while(условие){
2
3 // действия
4 }
Опять же выведем с помощью while элементы массива:
1 var people = ["Tom", "Alice", "Bob", "Sam"];
2 var index = 0;
3 while(index < [Link]){
4
5 [Link](people[index]);
6 index++;
7 }
Цикл while здесь будет выполняться, пока значение index не станет равным длине
массива.
do..while
В цикле do сначала выполняется код цикла, а потом происходит проверка условия в
инструкции while. И пока это условие истинно, цикл повторяется. Например:
1 var x = 1;
2 do{
3 [Link](x * x);
4 x++;
5 }while(x < 10)
Здесь код цикла сработает 9 раз, пока x не станет равным 10. При этом цикл do
гарантирует хотя бы однократное выполнение действий, даже если условие в
инструкции while не будет истинно.
Операторы continue и break
Иногда бывает необходимо выйти из цикла до его завершения. В этом случае мы
можем воспользоваться оператором break:
43
1 var array = [ 1, 2, 3, 4, 5, 12, 17, 6, 7 ];
2 for (var i = 0; i < [Link]; i++)
3 {
4 if (array[i] > 10)
5 break;
6 [Link](array[i] + "</br>");
}
7
Данный цикл перебирает все элементы массива, однако последние четыре элемента
не будут выведены в браузере, поскольку поверка if (array[i] > 10) прервет
выполнение цикла с помощью оператора break, когда перебор массива дойдет до
элемента 12.
Если нам надо просто пропустить итерацию, но не выходить из цикла, мы можем
применять оператор continue:
1 var array = [ 1, 2, 3, 4, 5, 12, 17, 6, 7 ];
2 for (var i = 0; i < [Link]; i++)
3 {
4 if (array[i] > 10)
5 continue;
6 [Link](array[i] + "</br>");
}
7
В этом случае, если программа встретит в массиве число, больше 10, то это число не
будет выводиться в браузере:
Функциональное программирование
Функции
Последнее обновление: 09.04.2018
44
Функции представляют собой набор инструкций, выполняющих определенное
действие или вычисляющих определенное значение.
Синтаксис определения функции:
1 function имя_функции([параметр [, ...]]){
2
3 // Инструкции
4 }
Определение функции начинается с ключевого слова function, после которого
следует имя функции. Наименование функции подчиняется тем же правилам, что и
наименование переменной: оно может содержать только цифры, буквы, символы
подчеркивания и доллара ($) и должно начинаться с буквы, символа подчеркивания
или доллара.
После имени функции в скобках идет перечисление параметров. Даже если
параметров у функции нет, то просто идут пустые скобки. Затем в фигурных скобках
идет тело функции, содержащее набор инструкций.
Определим простейшую функцию:
1 function display(){
2
3 [Link]("функция в JavaScript");
4 }
Данная функция называется display(). Она не принимает никаких параметров и все,
что она делает, это пишет на веб-страницу строку.
Однако простого определения функции еще недостаточно, чтобы она заработала. На
надо еще ее вызвать:
1 <!DOCTYPE html>
2 <html>
<head>
45
3
<meta charset="utf-8" />
4
</head>
5
<body>
6
<script>
7
function display(){
8
9
[Link]("функция в JavaScript");
10
}
11
display();
12 </script>
13 </body>
14 </html>
15
Необязательно давать функциям определенное имя. Можно использовать анонимные
функции:
1 var display = function(){ // определение функции
2
3 [Link]("функция в JavaScript");
4 }
5 display();
Фактически мы определяем переменную display и присваиваем ей ссылку на функцию.
А затем по имени переменной функция вызывается.
Также мы можем динамически присваивать функции для переменной:
1 function goodMorning(){
2
3 [Link]("Доброе утро");
4 }
function goodEvening(){
5
46
6
7 [Link]("Добрый вечер");
8 }
9 var message = goodMorning;
10 message(); // Доброе утро
11 message = goodEvening;
12 message(); // Добрый вечер
Параметры функции
Рассмотрим передачу параметров:
1 function display(x){ // определение функции
2
3 var z = x * x;
4 [Link](x + " в квадрате равно " + z);
5 }
6
7 display(5); // вызов функции
Функция display принимает один параметр - x. Поэтому при вызове функции мы можем
передать для него значение, например, число 5, как в данном случае.
Если функция принимает несколько параметров, то с помощью spread-оператора ...
мы можем передать набор значений для этих параметров из массива:
1 function sum(a, b, c){
2 let d = a + b + c;
3 [Link](d);
4 }
5 sum(1, 2, 3);
6 let nums = [4, 5, 6];
sum(...nums);
7
47
Во втором случае в функцию передается числа из массива nums. Но чтобы
передавался не просто массив, как одно значение, а именно числа из этого массива,
применяется spread-оператор (многоточие ...).
Необязательные параметры
Функция может принимать множество параметров, но при этом часть или все
параметры могут быть необязательными. Если для параметров не передается
значение, то по умолчанию они имеют значение "undefined".
1 function display(x, y){
2
3 if(y === undefined) y = 5;
4 if(x === undefined) x = 8;
5 let z = x * y;
6 [Link](z);
7 }
8 display(); // 40
display(6); // 30
9
display(6, 4) // 24
10
Здесь функция display принимает два параметра. При вызове функции мы можем
проверить их значения. При этом, вызывая функцию, необязательно передавать для
этих параметров значения. Для проверки наличия значения параметров используется
сравнение со значением undefined.
Есть и другой способ определения значения для параметров по умолчанию:
1 function display(x = 5, y = 10){
2 let z = x * y;
3 [Link](z);
4 }
5 display(); // 50
6 display(6); // 60
display(6, 4) // 24
7
48
Если параметрам x и y не передаются значения, то они получаются в качестве
значений числа 5 и 10 соответствено. Такой способ более лаконичен и интуитивен,
чем сравнение с undefined.
При этом значение параметра по умолчанию может быть производным, представлять
выражение:
1 function display(x = 5, y = 10 + x){
2 let z = x * y;
3 [Link](z);
4 }
5 display(); // 75
6 display(6); // 96
display(6, 4) // 24
7
В данном случае значение параметра y зависит от значения x.
При необходимости мы можем получить все переданные параметры через глобально
доступный массив arguments:
1 function display(){
2 var z = 1;
3 for(var i=0; i<[Link]; i++)
4 z *= arguments[i];
5 [Link](z);
6 }
7 display(6); // 6
display(6, 4) // 24
8
display(6, 4, 5) // 120
9
При этом даже не важно, что при определении функции мы не указали никаких
параметров, мы все равно можем их передать и получить их значения через массив
arguments.
Неопределенное количество параметров
С помощью spread-оператора мы можем указать, что с помощью параметра можно
передать переменное количество значений:
49
1 function display(season, ...temps){
2 [Link](season);
3 for(index in temps){
4 [Link](temps[index]);
5 }
6 }
7 display("Весна", -2, -3, 4, 2, 5);
display("Лето", 20, 23, 31);
8
В данном случае второй параметр ...temps указывает, что вместо него можно
передать разное количество значений. В самой функции temps фактически
представляет массив переданных значений, которые мы можем получить. При этом
несмотря на это, при вызове функции в нее передается не массив, а именно
отдельные значения.
Консольный вывод:
Весна
-2
-3
Лето
20
23
31
Результат функции
Функция может возвращать результат. Для этого используется оператор return:
1 var y = 5;
2 var z = square(y);
3 [Link](y + " в квадрате равно " + z);
4
function square(x) {
5
return x * x;
50
6
}
7
После оператора return идет значение, которое надо возвратить из метода. В данном
случае это квадрат числа х.
После получения результата функции мы можем присвоить его какой-либо другой
переменной:
1 var z = square(y);
Функции в качестве параметров
Функции могут выступать в качестве параметров других функций:
1
function sum(x, y){
2
return x + y;
3 }
4
5 function subtract(x, y){
6 return x - y;
7 }
8
9 function operation(x, y, func){
10
11 var result = func(x, y);
12 [Link](result);
13 }
14
[Link]("Sum");
15
operation(10, 6, sum); // 16
16
17
[Link]("Subtract");
18
operation(10, 6, subtract); // 4
19
51
Функция operation принимает три параметра: x, y и func. func - представляет
функцию, причем на момент определения operation не важно, что это будет за
функция. Единственное, что известно, что функция func может принимать два
параметра и возвращать значение, которое затем отображается в консоли браузера.
Поэтому мы можем определить различные функции (например, функции sum и
subtract в данном случае) и передавать их в вызов функции operation.
Возвращение функции из функции
Одна функция может возвращать другую функцию:
1
function menu(n){
2
3 if(n==1) return function(x, y){ return x+y;}
4 else if(n==2) return function(x, y){ return x - y;}
5 else if(n==3) return function(x, y){ return x * y;}
6 return undefined;
7 }
8
9 for(var i=1; i < 5; i++){
10 var action = menu(i);
11 if(action!==undefined){
var result = action(5, 4);
12
[Link](result);
13
}
14
}
15
В данном случае функция menu в зависимости от переданного в нее значения
возвращает одну из трех функций или undefined.
Область видимости переменных
Последнее обновление: 05.04.2018
52
Все переменные в JavaScript имеют определенную область видимости, в пределах
которой они могут действовать.
Глобальные переменные
Все переменные, которые объявлены вне функций, являются глобальными:
1
<!DOCTYPE html>
2
<html>
3
<head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <script>
8 var x = 5;
9 let d = 8;
10 function displaySquare(){
11
12 var z = x * x;
[Link](z);
13
}
14
</script>
15
</body>
16
</html>
17
Здесь переменные x и d являются глобальными. Они доступны из любого места
программы.
А вот переменная z глобальной не является, так как она определена внутри функции.
Локальные переменные
Переменная, определенная внутри функции, является локальной:
53
1 function displaySquare(){
2
3 var z = 10;
4 [Link](z);
5
6 let b = 8;
7 [Link](b);
8 }
Переменные z и b являются локальными, они существуют только в пределах функции.
Вне функции их нельзя использовать:
1 function displaySquare(){
2
3 var z = 10;
4 [Link](z);
5 }
6 [Link](z); //ошибка, так как z не определена
Когда функция заканчивает свою работу, то все переменные, определенные в
функции, уничтожаются.
Сокрытие переменных
Что если у нас есть две переменных - одна глобальная, а другая локальная, которые
имеют одинаковое имя:
1 var z = 89;
2 function displaySquare(){
3
4 var z = 10;
5 [Link](z); // 10
6 }
7 displaySquare(); // 10
54
В этом случае в функции будет использоваться та переменная z, которая определена
непосредственно в функции. То есть локальная переменная скроет глобальную.
var или let
При использовании оператора let каждый блок кода определяет новую область
видимости, в которой существует переменная. Например, мы можем одновременно
определить переменную на уровне блока и на уровне функции:
1 let z = 10;
2 function displayZ(){
3
4 let z = 20;
5
6 {
7 let z = 30;
8 [Link]("Block:", z);
9 }
10
11 [Link]("Function:", z);
}
12
13
displayZ();
14
[Link]("Global:", z);
15
Здесь внутри функции displayZ определен блок кода, в котором определена
переменная z. Она скрывает глобальную переменную и переменную z, определенную
на уровне функции. В реальной программе блок мог быть предеставлять вложенную
функцию, блок цикла for или конструкции if. Но в любом случае такой блок
определяет новую область видимости, вне которого переменная не существует.
И в данном случае мы получим следующий консольный вывод:
Block: 30 Function: 20 Global: 10
С помощью оператора var мы не можем определить одновременно переменную с
одним и тем же именем и в функции, и в блоке кода в этой функции:
55
1 function displaySquare(){
2
3 var z = 20;
4
5 {
6 var z = 30; // Ошибка ! Переменная z уже определена
7 [Link]("Block:", z);
8 }
9 [Link]("Function:", z);
}
10
То есть с помощью var мы можем определить переменную с одним именем либо на
уровне функции, либо на уровне блока кода.
Константы
Все, что относится к оператору let, относится и к оператору const, который позволяет
определить константы. Блоки кода задают область видимости констант, а константы,
определенные на вложенных блоках кода, скрывают внешние константы с тем же
именем:
1 const z = 10;
2 function displayZ(){
3
4 const z = 20;
5
{
6
const z = 30;
7
[Link]("Block:", z); // 30
8
}
9
[Link]("Function:", z); // 20
10
}
11
12
displayZ();
56
13
[Link]("Global:", z); // 10
14
Необъявленные переменные
Если мы не используем это ключевое слово при определении переменной в функции,
то такая переменная будет глобальной. Например:
1 function bar(){
2 foo = "25";
3 }
4 bar();
5 [Link](foo); // 25
Несмотря на то, что вне функции bar переменная foo нигде не определяется, тем не
менее она доступна вне функции во внешнем контексте.
Иначе было бы если бы мы не только присваивали значение переменной, но и
определяли бы ее:
1 function bar(){
2 var foo = "25";
3 }
4
5 bar();
6 [Link](foo); // ошибка
strict mode
Определение глобальных переменных в функциях может вести к потенциальным
ошибкам. Чтобы их избежать используется строгий режим или strict mode:
1 "use strict";
2 function bar(){
3 foo = "25";
}
4
5
bar();
6
57
7 [Link](foo);
В этом случае мы получим ошибку SyntaxError: Unexpected identifier, которая
говорит о том, что переменная foo не определена.
Установить режим strict mode можно двумя способами:
добавить выражение "use strict" в начало кода JavaScript, тогда strict mode
будет применяться для всего кода
добавить выражение "use strict" в начало тела функции, тогда strict mode будет
применяться только для этой функции
Замыкания и функции IIFE
Последнее обновление: 30.03.2018
Замыкания
Замыкание (closure) представляют собой конструкцию, когда функция, созданная в
одной области видимости, запоминает свое лексическое окружение даже в том
случае, когда она выполняет вне своей области видимости.
Замыкание технически включает три компонента:
внешняя функция, которая определяет некоторую область видимости и в
которой определены некоторые переменные - лексическое окружение
переменные (лексическое окружение), которые определены во внешней
функции
вложенная функция, которая использует эти переменные
1 function outer(){ // внешняя функция
2 var n; // некоторая переменная
3 return inner(){ // вложенная функция
// действия с переменной n
4
58
5 }
6 }
Рассмотрим замыкания на простейшем примере:
1 function outer(){
2 let x = 5;
3 function inner(){
4 x++;
[Link](x);
5
};
6
return inner;
7
}
8
let fn = outer(); // fn = inner, так как функция outer возвращает
9 функцию inner
10 // вызываем внутреннюю функцию inner
11 fn(); // 6
12 fn(); // 7
13 fn(); // 8
Здесь функция outer задает область видимости, в которой определены внутренняя
функция inner и переменная x. Переменная x представляет лексическое окружение
для функции inner. В самой функции inner инкрементируем переменную x и выводим
ее значение на консоль. В конце функция outer возвращает функцию inner.
Далее вызываем функцию outer:
1 let fn = outer();
Поскольку функция outer возвращает функцию inner, то переменная fn будет хранить
ссылку на функцию inner. При этом эта функция запомнила свое окружение - то есть
внешнюю переменную x.
Далее мы фактически три раза вызываем функцию Inner, и мы видим, что переменная
x, которая определена вне функции inner, инкрементируется:
1 fn(); // 6
2 fn(); // 7
59
3 fn(); // 8
То есть несмотря на то, что переменная x определена вне функции inner, эта функция
запомнила свое окружение и может его использовать, несомотря на то, что она
вызывается вне функции outer, в которой была определена. В этом и суть замыканий.
Рассмотрим еще один пример:
1 function multiply(n){
2 var x = n;
3 return function(m){ return x * m;};
4 }
5 var fn1 = multiply(5);
6 var result1 = fn1(6); // 30
7 [Link](result1); // 30
8
9 var fn2= multiply(4);
var result2 = fn2(6); // 24
10
[Link](result2); // 24
11
Итак, здесь вызов функции multiply() приводит к вызову другой внутренней
функции. Внутренняя же функция:
1 function(m){ return x * m;};
запоминает окружение, в котором она была создана, в частности, значение
переменной x.
В итоге при вызове функции multiply определяется переменная fn1, которая и
представляет собой замыкание, то есть объединяет две вещи: функцию и окружение,
в котором функция была создана. Окружение состоит из любой локальной
переменной, которая была в области действия функции multiply во время создания
замыкания.
То есть fn1 — это замыкание, которое содержит и внутреннюю функцию function(m){
return x * m;}, и переменную x, которая существовала во время создания
замыкания.
60
При создании двух замыканий: fn1 и fn2, для каждого из этих замыканий создается
свое окружение.
При этом важно не запутаться в параметрах. При определении замыкания:
1 var fn1 = multiply(5);
Число 5 передается для параметра n функции multiply.
При вызове внутренней функции:
1 var result1 = fn1(6);
Число 6 передается для параметра m во внутреннюю функцию function(m){ return x
* m;};.
Также мы можем использовать другой вариант для вызова замыкания:
1 function multiply(n){
2 var x = n;
3 return function(m){ return x * m;};
4 }
5 var result = multiply(5)(6); // 30
6 [Link](result);
Самовызывающиеся функции
Обычно определение функции отделяется от ее вызова: сначала мы определяем
функцию, а потом вызываем. Но это необязательно. Мы также можем создать такие
функции, которые будут вызываться сразу при определении. Такие функции еще
называют Immediately Invoked Function Expression (IIFE).
1 (function(){
2 [Link]("Привет мир");
3 }());
4
(function (n){
5
6
var result = 1;
7
61
8 for(var i=1; i<=n; i++)
9 result *=i;
10 [Link]("Факториал числа " + n + " равен " + result);
11 }(4));
Подобные функции заключаются в скобки, и после определения функции идет в
скобках передача параметров.
Паттерн Модуль
Последнее обновление: 26.06.2018
Паттерн "Модуль" базируется на замыканиях и состоит из двух компонентов: внешняя
функция, которая определяет лексическое окружение, и возвращаемый набор
внутренних функций, которые имеют доступ к этому окружению.
Определим простейший модуль:
1 let foo = (function(){
2 let obj = {greeting: "hello"};
3
4 return {
5 display: function(){
6 [Link]([Link]);
7 }
8 }
9 })();
10 [Link](); // hello
Здесь определена переменная foo, которая представляет результат анонимной
функции. Внутри подобной функции определен объект obj с некоторыми данными.
Сама анонимная функция возвращает объект, который определяет функцию display.
Возвращаемый объект определяет общедоступый API, через который мы можем
обращаться к данным, определенным внутри модуля.
1 return {
2 display: function(){
3 [Link]([Link]);
4 }
62
5 }
Такая конструкция позволяет закрыть некоторый набор данных в рамках функции-
модуля и опосредовать доступ к ним через определенный API - возвращаемые
внутренние функции.
Рассмотрим чуть более сложный пример:
1 let calculator = (function(){
2 let data = { number: 0};
3
4 return {
5 sum: function(n){
6 [Link] += n;
7 },
8 subtract: function(n){
9 [Link] -= n;
10 },
11 display: function(){
12 [Link]("Result: ", [Link]);
13 }
14 }
15 })();
16 [Link](10);
17 [Link](3);
18 [Link](); // Result: 13
19 [Link](4);
20 [Link](); // Result: 9
Данный модуль представляет примитивный калькулятор, который выполняет три
операции: сложение, вычитание и вывод результата.
Все данные инкапсулированы в объекте data, который хранит результат операции.
Все операции представлены тремя возвращаемыми функциями: sum, subtract и
display. Через эти функции мы можем управлять результатом калькулятора извне.
Рекурсивные функции
Последнее обновление: 1.11.2015
Среди функций отдельно можно выделить рекурсивные функции. Их суть состоит в
том, что функция вызывает саму себя.
63
Например, рассмотрим функцию, определяющую факториал числа:
1 function getFactorial(n){
2 if (n === 1){
3 return 1;
4 }
5 else{
6
7 return n * getFactorial(n - 1);
8 }
9 }
10 var result = getFactorial(4);
11 [Link](result); // 24
Функция getFactorial() возвращает значение 1, если параметр n равен 1, либо
возвращает результат опять же функции getFactorial, то в нее передается значение n-
1. Например, при передаче числа 4, у нас образуется следующая цепочка вызовов:
1 var result = 4 * getFactorial(3);
2 var result = 4 * 3 * getFactorial(2);
3 var result = 4 * 3 * 2 * getFactorial(1);
4 var result = 4 * 3 * 2 * 1; // 24
Рассмотрим другой пример - определение чисел Фибоначчи:
1 function getFibonachi(n)
2 {
3 if (n === 0){
4 return 0;
5 }
6 if (n === 1){
7 return 1;
8 }
9 else{
10 return getFibonachi(n - 1) + getFibonachi(n - 2);
11 }
12 }
13 var result = getFibonachi(8); //21
14 [Link](result); // 21
Переопределение функций
Последнее обновление: 1.11.2015
64
Функции обладают возможностью для переопределения поведения. Переопределение
происходит с помощью присвоения анонимной функции переменной, которая
называется так же, как и переопределяемая функция:
1 function display(){
2 [Link]("Доброе утро");
3 display = function(){
4 [Link]("Добрый день");
5 }
6 }
7
8 display(); // Доброе утро
9 display(); // Добрый день
При первом срабатывании функции действует основной блок операторов функции, в
частности, в данном случае выводится сообщение "Доброе утро". И при первом
срабатывании функции display также происходит ее переопределение. Поэтому при
всех последующих вызовах функции срабатывает ее переопределенная версия, а на
консоль будет выводиться сообщение "Добрый день".
Но при переопределении функции надо учитывать некоторые нюансы. В частности,
попробуем присвоить ссылку на функцию переменной и через эту переменную
вызвать функцию:
1 function display(){
2 [Link]("Доброе утро");
3 display = function(){
4 [Link]("Добрый день");
5 }
6 }
7 // присвоение ссылки на функцию до переопределения
8 var displayMessage = display;
9 display(); // Доброе утро
10 display(); // Добрый день
11 displayMessage(); // Доброе утро
12 displayMessage(); // Доброе утро
Здесь переменная displayMessage получает ссылку на функцию display до ее
переопределения. Поэтому при вызове displayMessage() будет вызываться
непереопределенная версия функции display.
Но допустим, мы определили переменную displayMessage уже после вызова функции
display:
1 display(); // Доброе утро
2 display(); // Добрый день
3 var displayMessage = display;
4 displayMessage(); // Добрый день
65
5 displayMessage(); // Добрый день
В этом случае переменная displayMessage будет указывать на переопределенную
версию функции display.
Hoisting
Последнее обновление: 22.11.2016
Hoisting представляет процесс доступа к переменным до их определения. Возможно,
данная концепция выглядит немного странно, но она связана с работой компилятора
JavaScript. Компиляция кода происходит в два прохода. При первом проходе
компилятор получает все объявления переменных, все идентификаторы. При этом
никакой код не выполняется, методы не вызываются. При втором проходе собственно
происходит выполнение. И даже если переменная определена после
непосредственного использования, ошибки не возникнет, так как при первом проходе
компилятору уже известны все переменные.
То есть как будто происходит поднятие кода с определением переменных и функций
вверх до их непосредственного использования. Поднятие на английский переводится
как hoisting, сообственно поэтому данный процесс так и называется.
Переменные, которые попадают под hoisting, получают значение undefined.
Например, возьмем следующий простейший код:
1 [Link](foo);
Его выполнение вызовет ошибку ReferenceError: foo is not defined
Добавим определение переменной:
1 [Link](foo); // undefined
2 var foo = "Tom";
В этом случае консоль выведет значение "undefined". При первом проходе компилятор
узнает про существование переменной foo. Она получает значение undefined. При
втором проходе вызывается метод [Link](foo).
Возьмем другой пример:
1 var c = a * b;
66
2 var a = 7;
3 var b = 3;
4 [Link](c); // NaN
Здесь та же ситуация. Переменные a и b используются до опеределения. По
умолчанию им присваиваются значения undefined. А если умножить undefined на
undefined, то получим Not a Number (NaN).
Все то же самое относится и к использованию функций. Мы можем сначала вызвать
функцию, а потом уже ее определить:
1 display();
2
3 function display(){
4 [Link]("Hello Hoisting");
5 }
Здесь функция display благополучно отработает, несмотря на то, что она определена
после вызова.
Но от этой ситуации надо отличать тот случай, когда функция определяется в виде
переменной:
1 display();
2
3 var display = function (){
4 [Link]("Hello Hoisting");
5 }
В данном случае мы получим ошибку TypeError: display is not a function. При
первом проходе компилятор также получит переменную display и присвоет ей
значение undefined. При втором проходе, когда надо будет вызывать функцию, на
которую будет ссылаться эта переменная, компилятор увидит, что вызывать то
нечего: переменная display пока еще равна undefined. И будет выброшена ошибка.
Поэтому при определении переменных и функций следует учитывать перепетии
такого аспекта как hoisting.
Передача параметров по значению и по
ссылке
Последнее обновление: 27.03.2018
67
Передача параметров по значению
Строки, числа, логические значения передаются в функцию по значению. Иными
словами при передаче значения в функцию, эта функция получает копию данного
значения. Рассмотрим, что это значит в практическом плане:
1 function change(x){
2 x = 2 * x;
3 [Link]("x in change:", x);
4 }
5
6 var n = 10;
7 [Link]("n before change:", n); // n before change: 10
8 change(n); // x in change: 20
[Link]("n after change:", n); // n after change: 10
9
Функция change получает некоторое число и увеличивает его в два раза. При вызове
функции change ей передается число n. Однако после вызова функции мы видим, что
число n не изменилось, хотя в самой функции произошло увеличение значения
параметра. Потому что при вызове функция change получает копию значения
переменной n. И любые изменения с этой копией никак не затрагивают саму
переменную n.
Передача по ссылке
Объекты и массивы передаются по ссылке. То есть функция получает сам объект или
массив, а не их копию.
1 function change(user){
2 [Link] = "Tom";
3 }
4
var bob ={
5
name: "Bob"
6
};
7
68
8 [Link]("before change:", [Link]); // Bob
9 change(bob);
10 [Link]("after change:", [Link]); // Tom
В данном случае функция change получает объект и меняет его свойство name. В
итоге мы увидим, что после вызова функции изменился оригинальный объект bob,
который передавался в функцию.
Однако если мы попробуем переустановить объект или массив полностью,
оригинальное значение не изменится.
1
function change(user){
2 // полная переустановка объекта
3 user= {
4 name:"Tom"
5 };
6 }
7
8 var bob ={
9 name: "Bob"
10 };
[Link]("before change:", [Link]); // Bob
11
change(bob);
12
[Link]("after change:", [Link]); // Bob
13
То же самое касается массивов:
1 function change(array){
2 array[0] = 8;
3 }
function changeFull(array){
4
array = [9, 8, 7];
5
}
6
69
7
var numbers = [1, 2, 3];
8
9
[Link]("before change:", numbers); // [1, 2, 3]
10
change(numbers);
11
[Link]("after change:", numbers); // [8, 2, 3]
12
changeFull(numbers);
13
[Link]("after changeFull:", numbers); // [8, 2, 3]
14
Стрелочные функции
Последнее обновление: 09.04.2018
Стрелочные функции (arrow functions) представляют сокращенную версию обычных
функций. Стрелочные функции образуются с помощью знака стрелки (=>), перед
которым в скобках идут параметры функции, а после - собственно тело функции.
Например:
1 let sum = (x, y) => x + y;
2 let a = sum(4, 5); // 9
3 let b = sum(10, 5); // 15
В данном случае функция (x, y) => x + y осуществляет сложение двух чисел и
присваивается переменной sum. Функция принимает два параметра - x и y. Ее тело
составляет сложение значений этих параметров. И поскольку после стрелки
фактически идет конкретное значение, которое представляет сумму чисел, то
функция возвращает это значение. И мы можем через переменную sum вызвать
данную функцию и получить ее результат в переменные a и b.
Если после стрелки идет операция или выражение, которое возвращает значение, то
это значение фактически возвращается из стрелочной функции. Но также в качестве
тела функции может примяться выражение, которое ничего не возвращает и просто
выполняет некоторое действие:
1 let sum = (x, y) => [Link](x + y);
2 sum(4, 5); // 9
3 sum(10, 5); // 15
70
В данном случае функция [Link]() ничего не возвращает, и соответственно
функция sum также не возвращает никакого результата.
Если функция принимает один параметр, то скобки вокруг него можно опустить:
1 var square = n => n * n;
2
3 [Link](square(5)); // 25
4 [Link](square(6)); // 36
5 [Link](square(-7)); // 49
Если тело функции представляет набор выражений, то они облекаются в фигурные
скобки:
1 var square = n => {
2 let result = n * n;
3 return result;
4 }
5
6 [Link](square(5)); // 25
Для возвращения результата из функции в таком случае применяется стандартный
оператор return.
Особо следует остановиться на случае, когда стрелочная функция возвращает
объект:
1 let user = (userName, userAge) => ({name: userName, age: userAge});
2
3 let tom = user("Tom", 34);
4 let bob = user("Bob", 25);
5
6 [Link]([Link], [Link]); // "Tom", 34
7 [Link]([Link], [Link]); // "Bob", 25
Объект также определяется с помощью фигурных скобок, но при этом он заключается
в круглые скобки.
Если стрелочная функция не принимает никаких параметров, то ставятся пустые
скобки:
1 var hello = ()=> [Link]("Hello World");
2 hello(); // Hello World
3 hello(); // Hello World
Объектно-ориентированное
программирование
71
Последнее обновление: 08.04.2018
Объектно-ориентированное программирование на сегодняшний день является одной
из господствующих парадигм в разработке приложений, и в JavaScript мы также
можем использовать все преимущества ООП. В то же время применительно к
JavaScript объектно-ориентированное программирование имеет некоторые
особенности.
Объекты
В прошлых темах мы работали с примитивными данными - числами, строками, но
данные не всегда представляют примитивные типы. Например, если в нашей
программе нам надо описать сущность человека, у которого есть имя, возраст, пол и
так далее, то естественно мы не сможем представить сущность человека в виде
числа или строки. Нам потребуется несколько строк или чисел, чтобы должным
образом описать человека. В этом плане человек будет выступать как сложная
комплексная структура, у которого будут отдельные свойства - возраст, рост, имя,
фамилия и т.д.
Для работы с подобными структурами в JavaScript используются объекты. Каждый
объект может хранить свойства, которые описывают его состояние, и методы,
которые описывают его поведение
Создание нового объекта
Есть несколько способов создания нового объекта.
Первый способ заключается в использовании конструктора Object:
1 var user = new Object();
В данном случае объект называется user. Он определяется также, как и любая
обычная переменная с помощью ключевого слова var.
Выражение new Object() представляет вызов конструктора - функции, создающей
новый объект. Для вызова конструктора применяется оператор new. Вызов
конструктора фактически напоминает вызов обычной функции.
Второй способ создания объекта представляет использование фигурных скобок:
72
1 var user = {};
На сегодняшний день более распространенным является второй способ.
Свойства объекта
После создания объекта мы можем определить в нем свойства. Чтобы определить
свойство, надо после названия объекта через точку указать имя свойства и присвоить
ему значение:
1 var user = {};
2 [Link] = "Tom";
3 [Link] = 26;
В данном случае объявляются два свойства name и age, которым присваиваются
соответствующие значения. После этого мы можем использовать эти свойства,
например, вывести их значения в консоли:
1 [Link]([Link]);
2 [Link]([Link]);
Также можно определить свойства при определении объекта:
1 var user = {
2
3 name: "Tom",
4 age: 26
5 };
В этом случае для присвоения значения свойству используется символ двоеточия, а
после определения свойства ставится запятая (а не точка с запятой).
Кроме того, доступен сокращенный способ определения свойств:
1 var name = "Tom";
2 var age = 34;
3 var user = {name, age};
[Link]([Link]); // Tom
4
73
5 [Link]([Link]); // 34
В данном случае названия переменных также являются и названиями свойств
объекта. И таким образом можно создавать более сложные конструкции:
1 var name = "Tom";
2 var age = 34;
3 var user = {name, age};
4
5 var teacher = {user, course: "JavaScript"};
6 [Link]([Link]); // {name: "Tom", age: 34}
7 [Link]([Link]); // JavaScript
Методы объекта
Методы объекта определяют его поведение или действия, которые он производит.
Методы представляют собой функции. Например, определим метод, который бы
выводил имя и возраст человека:
1 var user = {};
2 [Link] = "Tom";
3 [Link] = 26;
4 [Link] = function(){
5
6 [Link]([Link]);
7 [Link]([Link]);
8 };
9
// вызов метода
10
[Link]();
11
Как и в случае с функциями методы сначала определяются, а потом уже вызываются.
Также методы могут определяться непосредственно при определении объекта:
1 var user = {
74
2
3 name: "Tom",
4 age: 26,
5 display: function(){
6
7 [Link]([Link]);
8 [Link]([Link]);
9 }
};
10
Как и в случае со свойствами, методу присваивается ссылка на функцию с помощью
знака двоеточия.
Чтобы обратиться к свойствам или методам объекта внутри этого объекта,
используется ключевое слово this. Оно означает ссылку на текущий объект.
Также можно использовать сокращенный способ определения методов, когда
двоеточие и слово function опускаются:
1
var user = {
2
3 name: "Tom",
4 age: 26,
5 display(){
6
7 [Link]([Link], [Link]);
8 },
9 move(place){
10 [Link]([Link], "goes to", place);
11 }
};
12
[Link](); // Tom 26
13
[Link]("the shop"); // Tom goes to the shop
14
75
Синтаксис массивов
Существует также альтернативный способ определения свойств и методов с помощью
синтаксиса массивов:
1 var user = {};
2 user["name"] = "Tom";
3 user["age"] = 26;
4 user["display"] = function(){
5
6 [Link]([Link]);
7 [Link]([Link]);
8 };
9
// вызов метода
10
user["display"]();
11
Название каждого свойства или метода заключается в кавычки и в квадратные
скобки, затем им также присваивается значение. Например, user["age"] = 26.
При обращении к этим свойствам и методам можно использовать либо нотацию точки
([Link]), либо обращаться так: user["name"]
Строки в качестве свойств и методов
Также следует отметить, что названия свойств и методов объекта всегда
представляют строки. То есть мы могли предыдущее определение объекта
переписать так:
1 var user = {
2 "name": "Tom",
3 "age": 26,
"display": function(){
4
5
[Link]([Link]);
6
[Link]([Link]);
7
}
76
8
};
9
// вызов метода
10
[Link]();
11
С одной стороны, разницы никакой нет между двумя определениями. С другой
стороны, бывают случаи, где заключение названия в строку могут помочь. Например,
если название свойства состоит из двух слов, разделенных пробелом:
1 var user = {
2 name: "Tom",
3 age: 26,
4 "full name": "Tom Johns",
5 "display info": function(){
6
7 [Link]([Link]);
8 [Link]([Link]);
9 }
};
10
[Link](user["full name"]);
11
user["display info"]();
12
Только в этом случае для обращении к подобным свойствам и методам мы должны
использовать синтаксис массивов.
Удаление свойств
Выше мы посмотрели, как можно динамически добавлять новые свойства к объекту.
Однако также мы можем удалять свойства и методы с помощью оператора delete. И
как и в случае с добавлением мы можем удалять свойства двумя способами. Певый
способ - использование нотации точки:
1 delete объект.свойство
Либо использовать синтаксис массивов:
1 delete объект["свойство"]
77
Например, удалим свойство:
1
var user = {};
2 [Link] = "Tom";
3 [Link] = 26;
4 [Link] = function(){
5
6 [Link]([Link]);
7 [Link]([Link]);
8 };
9
10 [Link]([Link]); // Tom
11 delete [Link]; // удаляем свойство
// альтернативный вариант
12
// delete user["name"];
13
[Link]([Link]); // undefined
14
После удаления свойство будет не определено, поэтому при попытке обращения к
нему, программа вернет значение undefined.
Вложенные объекты и массивы в объектах
Последнее обновление: 1.11.2015
Одни объекты могут содержать в качестве свойств другие объекты. Например, есть
объект страны, у которой можно выделить ряд свойств. Одно из этих свойств может
представлять столицу. Но у столицы мы также можем выделить свои свойства,
например, название, численность населения, год основания:
1 var country = {
2
3 name: "Германия",
4 language: "немецкий",
5 capital:{
78
6
7 name: "Берлин",
8 population: 3375000,
9 year: 1237
10 }
11 };
12 [Link]("Столица: " + [Link]); // Берлин
13 [Link]("Население: " + country["capital"]["population"]); // 3375000
14 [Link]("Год основания: " + [Link]["year"]); // 1237
Для доступа к свойствам таких вложенных объектов мы можем использовать
стандартную нотацию точки:
1 [Link]
Либо обращаться к ним как к элементам массивов:
1 country["capital"]["population"]
Также допустим смешанный вид обращения:
1 [Link]["year"]
В качестве свойств также могут использоваться массивы, в том числе массивы других
объектов:
1 var country = {
2
3 name: "Швейцария",
4 languages: ["немецкий", "французский", "итальянский"],
5 capital:{
6
7 name: "Берн",
8 population: 126598
9 },
10 cities: [
11 { name: "Цюрих", population: 378884},
12 { name: "Женева", population: 188634},
13 { name: "Базель", population: 164937}
14 ]
15 };
16
17 // вывод всех элементов из [Link]
18 [Link]("<h3>Официальные языки Швейцарии</h3>");
19 for(var i=0; i < [Link]; i++)
20 [Link]([Link][i] + "<br/>");
21
22 // вывод всех элементов из [Link]
79
23 [Link]("<h3>Города Швейцарии</h3>");
24 for(var i=0; i < [Link]; i++)
25 [Link]([Link][i].name + "<br/>");
В объекте country имеется свойство languages, содержащее массив строк, а также
свойство cities, хранящее массив однотипных объектов.
С этими массивами мы можем работать также, как и с любыми другими, например,
перебрать с помощью цикла for.
При переборе массива объектов каждый текущий элемент будет представлять
отдельный объект, поэтому мы можем обратиться к его свойствам и методам:
1 [Link][i].name
В итоге браузер выведет содержимое этих массивов:
Проверка наличия и перебор методов и
свойств
Последнее обновление: 1.11.2015
При динамическом определении в объекте новых свойств и методов перед их
использованием бывает важно проверить, а есть ли уже такие методы и свойства. Для
этого в javascript может использоваться оператор in:
1 var user = {};
2 [Link] = "Tom";
3 [Link] = 26;
[Link] = function(){
4
5
[Link]([Link]);
6
[Link]([Link]);
7
};
8
80
var hasNameProp = "name" in user;
9
[Link](hasNameProp); // true - свойство name есть в user
10
var hasWeightProp = "weight" in user;
11
[Link](hasWeightProp); // false - в user нет свойства или метода под
12 названием weight
Оператор in имеет следующий синтаксис: "свойство|метод" in объект - в кавычках
идет название свойства или метода, а после in - название объекта. Если свойство или
метод с подобным именем имеется, то оператор возвращает true. Если нет - то
возвращается false.
Альтернативный способ заключается на значение undefined. Если свойство или метод
равен undefined, то эти свойство или метод не определены:
1 var hasNameProp = [Link]!==undefined;
2 [Link](hasNameProp); // true
3 var hasWeightProp = [Link]!==undefined;
4 [Link](hasWeightProp); // false
И так как объекты представляют тип Object, а значит, имеет все его методы и
свойства, то объекты также могут использовать метод hasOwnProperty(), который
определен в типе Object:
1 var hasNameProp = [Link]('name');
2 [Link](hasNameProp); // true
3 var hasDisplayProp = [Link]('display');
4 [Link](hasDisplayProp); // true
5 var hasWeightProp = [Link]('weight');
6 [Link](hasWeightProp); // false
Перебор свойств и методов
С помощью цикла for мы можем перебрать объект как обычный массив и получить все
его свойства и методы и их значения:
1 var user = {};
2 [Link] = "Tom";
3 [Link] = 26;
81
4 [Link] = function(){
5
6 [Link]([Link]);
7 [Link]([Link]);
8 };
9 for(var key in user) {
10 [Link](key + " : " + user[key]);
}
11
И при запуске консоль браузера отобразит следующий вывод:
name : Tom
age : 26
display : function (){
[Link]([Link]);
[Link]([Link]);
Объекты в функциях
Последнее обновление: 1.11.2015
Функции могут возвращать значения. Но эти значения не обязательно должны
представлять примитивные данные - числа, строки, но также могут быть сложными
объектами.
Например, вынесем создание объекта user в отдельную функцию:
1 function createUser(pName, pAge) {
2 return {
3 name: pName,
4 age: pAge,
5 displayInfo: function() {
6 [Link]("Имя: " + [Link] + " возраст: " + [Link] +
7 "<br/>");
82
}
8
};
9
};
10
var tom = createUser("Tom", 26);
11
[Link]();
12
var alice = createUser("Alice", 24);
13
[Link]();
Здесь функция createUser() получает значения pName и pAge и по ним создает
новый объект, который является возвращаемым результатом.
Преимуществом вынесения создания объекта в функцию является то, что далее мы
можем создать несколько однотипных объектов с разными значениями.
Кроме того объект может передаваться в качестве параметра в функцию:
function createUser(pName, pAge) {
1 return {
2 name: pName,
3 age: pAge,
4 displayInfo: function() {
5 [Link]("Имя: " + [Link] + " возраст: " + [Link] +
6 "<br/>");
7 },
8 driveCar: function(car){
9 [Link]([Link] + " ведет машину " + [Link] +
10 "<br/>");
11 }
12 };
13 };
14
15 function createCar(mName, mYear){
16 return{
17 name: mName,
18 year: mYear
19 };
20 };
21 var tom = createUser("Том", 26);
22 [Link]();
23 var bently = createCar("Бентли", 2004);
[Link](bently);
Здесь используются две функции для создания пользователей и объекта машины.
Метод driveCar() объекта user в качестве параметра принимает объект car.
В итоге браузер нам выведет:
Имя: Том возраст: 26
83
Том ведет машину Бентли
Конструкторы объектов
Последнее обновление: 27.03.2018
Кроме создания новых объектов JavaScript предоставляет нам возможность создавать
новые типы объектов с помощью конструкторов. Так, одним из способов создания
объекта является применение конструктора типа Object:
1 var tom = new Object();
После создания переменной tom она будет вести себя как объект типа Object.
Конструктор позволяет определить новый тип объекта. Тип представляет собой
абстрактное описание или шаблон объекта. Можно еще провести следующую
аналогию. У нас у всех есть некоторое представление о человеке - наличие двух рук,
двух ног, головы, пищеварительной, нервной системы и т.д. Есть некоторый шаблон -
этот шаблон можно назвать типом. Реально же существующий человек является
объектом этого типа.
Определение типа может состоять из функции конструктора, методов и свойств.
Для начала определим конструктор:
1 function User(pName, pAge) {
[Link] = pName;
2
[Link] = pAge;
3
[Link] = function(){
4
[Link]("Имя: " + [Link] + "; возраст: " + [Link] +
5 "<br/>");
6 };
7 }
84
Конструктор - это обычная функция за тем исключением, что в ней мы можем
установить свойства и методы. Для установки свойств и методов используется
ключевое слово this:
1 [Link] = pName;
В данном случае устанавливаются два свойства name и age и один метод displayInfo.
Как правило, названия конструкторы в отличие от названий обычных функций
начинаются с большой буквы.
После этого в программе мы можем определить объект типа User и использовать его
свойства и методы:
1 var tom = new User("Том", 26);
2 [Link]([Link]); // Том
3 [Link]();
Чтобы вызвать конструктор, то есть создать объект типа User, надо использовать
ключевое слово new.
Подобным образом мы можем определить и другие типы и использовать их вместе:
1 // конструктор типа Car
2 function Car(mName, mYear){
3 [Link] = mName;
[Link] = mYear;
4
[Link] = function(){
5
[Link]("Модель: " + [Link] + " Год выпуска: " + [Link] +
6 "<br/>");
7 };
8 };
9 // конструктор типа User
10 function User(pName, pAge) {
11 [Link] = pName;
12 [Link] = pAge;
13 [Link] = function(car){
[Link]([Link] + " ведет машину " + [Link] + "<br/>");
14
85
15 };
16 [Link] = function(){
17 [Link]("Имя: " + [Link] + "; возраст: " + [Link] + "<br/>");
18 };
19 };
20
21 var tom = new User("Том", 26);
22 [Link]();
var bently = new Car("Бентли", 2004);
23
[Link](bently);
24
Оператор instanceof
Оператор instanceof позволяет проверить, с помощью какого конструктора создан
объект. Если объект создан с помощью определенного конструктора, то оператор
возвращает true:
1 var tom = new User("Том", 26);
2
3 var isUser = tom instanceof User;
4 var isCar = tom instanceof Car;
5 [Link](isUser); // true
6 [Link](isCar); // false
Расширение объектов. Prototype
Последнее обновление: 1.11.2015
Кроме непосредственного определения свойств и методов в конструкторе мы также
можем использовать свойство prototype. Каждая функция имеет
свойство prototype, представляющее прототип функции. То есть
свойство [Link] представляет прототип объектов User. И любые свойства и
86
методы, которые будут определены в [Link], будут общими для всех
объектов User.
Например, после определения объекта User нам потребовалось добавить к нему
метод и свойство:
function User(pName, pAge) {
1
[Link] = pName;
2
[Link] = pAge;
3
[Link] = function(){
4
[Link]("Имя: " + [Link] + "; возраст: " + [Link] +
5
"<br/>");
6
};
7
};
8
9
[Link] = function(){
10
[Link]([Link] + " говорит: 'Привет!'<br/>");
11
};
12
[Link] = 110;
13
14
var tom = new User("Том", 26);
15
[Link]();
16
var john = new User("Джон", 28);
17
[Link]();
18
[Link]([Link]); // 110
19
[Link]([Link]); // 110
Здесь добавлены метод hello и свойство maxAge, и каждый объект User сможет их
использовать. Но важно заметить, что значение свойства maxAge будет одно и то же
для всех объектов, это разделяемое статическое свойство. В отличие, скажем, от
свойства [Link], которое хранит значение для определенного объекта.
В то же время мы можем определить в объекте свойство, которое будет назваться
также, как и свойство прототипа. В этом случае собственное свойство объекта будет
иметь приоритет перед свойством прототипа:
1 [Link] = 110;
2 var tom = new User("Том", 26);
3 var john = new User("Джон", 28);
4 [Link] = 99;
5 [Link]([Link]); // 99
6 [Link]([Link]); // 110
И при обращении к свойству maxAge javascript сначала ищет это свойство среди
свойств объекта, и если оно не было найдено, тогда обращается к свойствам
прототипа. То же самое касается и методов.
87
Инкапсуляция
Последнее обновление: 1.12.2019
Инкапсуляция является одним из ключевых понятий объектно-ориентированного
программирования и представляет сокрытие состояния объекта от прямого доступа
извне. По умолчанию все свойства объектов являются публичными, общедоступными,
и мы к ним можем обратиться из любого места программы.
1 function User(pName, pAge) {
2 [Link] = pName;
3 [Link] = pAge;
4 [Link] = function(){
5 [Link]("Имя: " + [Link] + "; возраст: " + [Link]);
6 };
7 };
8 var tom = new User("Том", 26);
9 [Link]=34;
10 [Link]([Link]);
Но мы можем их скрыть от доступа извне, сделав свойства локальными переменными:
1 function User (name) {
2 [Link] = name;
3 var _age = 1;
4 [Link] = function(){
5 [Link]("Имя: " + [Link] + "; возраст: " + _age);
6 };
7 [Link] = function() {
8 return _age;
9 }
10 [Link] = function(age) {
11 if(typeof age === "number" && age >0 && age<110){
12 _age = age;
13 } else {
14 [Link]("Недопустимое значение");
15 }
16 }
17 }
18
19 var tom = new User("Том");
20 [Link](tom._age); // undefined - _age - локальная переменная
21 [Link]([Link]()); // 1
88
22 [Link](32);
23 [Link]([Link]()); // 32
24 [Link]("54"); // Недопустимое значение
25 [Link](123); // Недопустимое значение
В конструкторе User объявляется локальная переменная _age вместо свойства age.
Как правило, названия локальных переменных в конструкторах начинаются со знака
подчеркивания.
Для того, чтобы работать с возрастом пользователя извне, определяются два метода.
Метод getAge() предназначен для получения значения переменной _age. Этот метод
еще называется геттер (getter). Второй метод - setAge, который еще называется
сеттер (setter), предназначен для установки значения переменной _age.
Плюсом такого подхода является то, что мы имеем больший контроль над доступом к
значению _age. Например, мы можем проверить какие-то сопутствующие условия, как
в данном случае проверяются тип значение (он должен представлять число), само
значение (возраст не может быть меньше 0).
Функция как объект. Методы call и apply
Последнее обновление: 1.11.2015
В JavaScript функция тоже является объектом - объектом Function и тоже имеет
прототип, свойства, методы. Все функции, которые используются в программе,
являются объектами Function и имеют все его свойства и методы.
Например, мы можем создать функцию с помощью конструктора Function:
1 var square = new Function('n', 'return n * n;');
2 [Link](square(5));
В конструктор Function может передаваться ряд параметров. Последний параметр
представляет собой само тело функции в виде строки. Фактически строка содержит
код javascript. Предыдущие аргументы содержат названия параметров. В данном
случае определяется функция возведения числа в квадрат, которая имеет один
параметр n.
Среди свойств объекта Function можно выделить следующие:
arguments: массив аргументов, передаваемых в функцию
length: определяет количество аргументов, которые ожидает функция
89
caller: определяет функцию, вызвавшую текущую выполняющуюся функцию
name: имя функции
prototype: прототип функции
С помощью прототипа мы можем определить дополнительные свойства:
1 function display(){
2
3 [Link]("привет мир");
4 }
5 [Link] ="Hello";
6
7 [Link]([Link]); // Hello
Среди методов надо отметить методы call() и apply().
Метод call() вызывает функцию с указанным значением this и аргументами:
1 function add(x, y){
2
3 return x + y;
4 }
5 var result = [Link](this, 3, 8);
6
7 [Link](result); // 11
this указывает на объект, для которого вызывается функция - в данном случае это
глобальный объект window. После this передаются значения для параметров.
При передаче объекта через первый параметр, мы можем ссылаться на него через
ключевое слово this:
1 function User (name, age) {
2 [Link] = name;
3 [Link] = age;
4 }
5 var tom = new User("Том", 26);
6 function display(){
7 [Link]("Ваше имя: " + [Link]);
8 }
9 [Link](tom); // Ваше имя: Том
В данном случае передается только одно значение, поскольку функция display не
принимает параметров. То есть функция будет вызываться для объекта tom.
Если нам не важен объект, для которого вызывается функция, то можно передать
значение null:
90
1 function add(x, y){
2
3 return x + y;
4 }
5 var result = [Link](null, 3, 8);
6
7 [Link](result); // 11
На метод call() похож метод apply(), который также вызывает функцию и в
качестве первого параметра также получает объект, для которого функция
вызывается. Только теперь в качестве второго параметра передается массив
аргументов:
1 function add(x, y){
2
3 return x + y;
4 }
5 var result = [Link](null, [3, 8]);
6
7 [Link](result); // 11
Наследование
Последнее обновление: 1.11.2015
JavaScript поддерживает наследование, то позволяет нам при создании новых типов
объектов при необходимости унаследовать их функционал от уже существующих.
Например, у нас может быть объект User, представляющий отдельного пользователя.
И также может быть объект Employee, который представляет работника. Но работник
также может являться пользователем и поэтому должен иметь все его свойства и
методы. Например:
1 // конструктор пользователя
2 function User (name, age) {
3 [Link] = name;
4 [Link] = age;
5 [Link] = function(){[Link]([Link] + " идет <br/>");}
6 [Link] = function(){
7 [Link]("Имя: " + [Link] + "; возраст: " + [Link] + "<br/>");
8 };
9 }
10 [Link] = 110;
91
11
// конструктор работника
12
function Employee(name, age, comp){
13
[Link](this, name, age);
14
[Link] = comp;
15
[Link] = function(){
16
[Link]("Имя: " + [Link] + "; возраст: " + [Link] + "; компани
17
"<br/>");
18
};
19
}
20
[Link] = [Link]([Link]);
21
22
var tom = new User("Том", 26);
23
var bill = new Employee("Билл", 32, "Google");
24
[Link]();
25
[Link]();
26
[Link]();
27
[Link]();
28
[Link]([Link]);
Здесь в начале определяет конструктор User и к его прототипу добавляется
свойство maxage. Затем определяется тип Employee.
В конструкторе Employee происходит обращение к конструктору User с помощью
вызова:
1 [Link](this, name, age);
Передача первого параметра позволяет вызвать функцию конструктора User для
объекта, создаваемого конструктором Employee. Благодаря этому все свойства и
методы, определенные в конструкторе User, также переходят на объект Employee.
Кроме того, необходимо унаследовать также и прототип User. Для этого служит
вызов:
1 [Link] = [Link]([Link]);
Метод [Link]() позволяет создать объект прототипа User, который затем
присваивается прототипу Employee. При этом при необходимости в прототипе
Employee мы также можем определить дополнительные свойства и методы.
При наследовании мы можем переопределять наследуемый функционал. Например,
Employee переопределяет метод displayInfo(), унаследованный от User, чтобы
включить в вывод этого метода новое свойство company.
В итоге браузер предоставит следующий вывод:
92
Ключевое слово this
Последнее обновление: 09.04.2018
Поведение ключевого слова this зависит от контекста, в котором оно используется, и
от того, в каком режиме оно используется - строгом или нестрогом.
Глобальный контекст
В глобальном контексте this ссылается на глобальный объект. В данном случае
поведение не зависит от режима (строгий или нестрогий):
1 [Link]("global alert");
2 [Link]("global console");
3
4 var currentDocument = [Link];
Но в данном случае использвание this избыточно.
Контекст функции
В пределах функции this ссылается на внешний контекст. Для функций,
определенных в глобальном контексте, - это объект Window, который представляет
окно браузера. Например:
1 function foo(){
2 var bar = "bar2";
3 [Link]([Link]);
}
4
5
var bar = "bar1";
6
7
foo(); // bar1
93
Если бы мы не использовали бы this, то обращение шло бы к локальной переменной,
определенной внутри функции.
1 function foo(){
2 var bar = "bar2";
3 [Link](bar);
4 }
5
6 var bar = "bar1";
7
8 foo(); // bar2
Но если бы мы использовали строгий режим (strict mode), то this в этом случае имело
бы значение undefined:
1 "use strict";
2 var obj = {
3 function foo(){
4 var bar = "bar2";
5 [Link]([Link]);
6 }
7 }
8
var bar = "bar1";
9
10
foo(); // ошибка - this - undefined
11
Контекст объекта
В контексте объекта, в том числе в его методах, ключевое слово this ссылается на
этот же объект:
1 var o = {
94
2 bar: "bar3",
3 foo: function(){
4 [Link]([Link]);
5 }
6 }
7 var bar = "bar1";
[Link](); // bar3
8
Примеры
Рассмотрим более сложный пример:
1 function foo(){
2 var bar = "bar2";
3 [Link]([Link]);
4 }
5
6 var o3 = {bar:"bar3", foo: foo};
7 var o4 = {bar:"bar4", foo: foo};
8
9 var bar = "bar1";
10
11 foo(); // bar1
[Link](); // bar3
12
[Link](); // bar4
13
Здесь определена глобальная переменная bar. И также в функции foo определена
локальная переменная bar. Значение какой переменной будет выводиться в функции
foo? Функция foo выводит значение глобальной переменной, так как данный скрипт
запускается в нестрогом режиме, а значит ключеое слово this в функции foo
ссылается на внешний контекст.
Иначе дело обстоит с объектами. Они определяют свой собственный контекст, в
котором существует свое свойство bar. И при вызове метода foo внешним контекстом
по отношению к функции будет контекст объектов o3 и o4.
95
Подобное поведение может привести к некоторому непонимаю в отдельных случаях.
Так, рассмотрим другую ситуацию:
1
var o1 = {
2 bar: "bar1",
3 foo: function(){
4 [Link]([Link]);
5 }
6 }
7 var o2 = {bar: "bar2", foo: [Link]};
8
9 var bar = "bar3";
10 var foo = [Link];
11
[Link](); // bar1
12
[Link](); // bar2
13
foo(); // bar3
14
Несмотря на то, что объект o2 использует метод foo из объекта o1, тем не менее
функция [Link] также будет искать значение для [Link] во внешнем котексте, то
есть в контексте объекта o2. А в объекте o2 это значение равно bar: "bar2".
То же самое с глобальной переменной foo, которая ссылается на ту же функцию, что и
метод [Link]. В этом случае также будет происходить поиск значения для [Link] во
внешним контексте, то есть в глобальном контексте, где определена переменная var
bar = "bar3".
Однако если мы вызываем функцию из другой функции, вызываемая функция также
будет использовать внешний контекст:
1 var bar = "bar2";
2
3 function daz(){
4 var bar = "bar5";
function maz(){
5
96
6
7 [Link]([Link]);
8 }
9 maz();
10 }
11 daz(); // bar2
Здесь функция daz в качестве [Link] использует значение переменной bar из
внешнего контекста, то есть значение глобальной переменной bar. Функция maz
также в качестве [Link] использует значение переменной bar из внешнего
контекста, а это значение [Link] из внешней функции daz, которое в свою очередь
представляет значение глобальной переменной bar. Поэтому в итоге консоль выведет
"bar2", а не "bar5".
Явная привязка
С помощью методов call() и apply() можно задать явную привязку функции к
определенному контексту:
1 function foo(){
2 [Link]([Link]);
3 }
4
5 var o3 = {bar: "bar3"}
6 var bar = "bar1";
7 foo(); // bar1
8 [Link](o3); // bar3
// или
9
// [Link](o3);
10
Во втором случае функция foo привязывается к объекту o3, который и определяет ее
контекст. Поэтому во втором случае консоль выведет "bar3".
Метод bind
Метод [Link](o) позволяет создать новую функцию с тем же телом и областью
видимости, что и функция f, но с привязкой к объекту o:
97
1 function foo(){
2 [Link]([Link]);
3 }
4
5 var o3 = {bar: "bar3"}
6 var bar = "bar1";
7 foo(); // bar1
8 var func = [Link](o3);
func(); // bar3
9
this и стрелочные функции
При работе с несколькими контекстами мы вынуждены учитывать, в каком контексте
определяется переменная. Например, возьмем следующий код:
1 var school ={
2 title: "Oxford",
3 courses: ["JavaScript", "TypeScript", "Java", "Go"],
4 printCourses: function(){
5 [Link](function(course){
6 [Link]([Link], course);
7 })
8 }
}
9
[Link]();
10
Функция printCourses проходит по всем курсам из массива и при их выводе
предваряет их значением свойства title. Однако на консоли при запуске программы
мы увидим следующее:
undefined "JavaScript"
undefined "TypeScript"
undefined "Java"
undefined "Go"
98
Мы видим, что значение [Link] не определено, так как this как контекст объекта
замещается глобальным контекстом. В этом случае нам надо передать подобное
значение [Link] или весь контекст объекта.
1 var school ={
2 title: "Oxford",
3 courses: ["JavaScript", "TypeScript", "Java", "Go"],
4 printCourses: function(){
5 var that = this;
6 [Link](function(course){
7 [Link]([Link], course);
8 })
}
9
}
10
[Link]();
11
Стрелочные функции также позволяют решить данную проблему:
1 var school ={
2 title: "Oxford",
3 courses: ["JavaScript", "TypeScript", "Java", "Go"],
4 printCourses: function(){
5 [Link]((course)=>[Link]([Link], course))
6 }
7 }
[Link]();
8
Контекстом для стрелочной функции в данном случае будет выступать контекст
объекта school. Соответственно, нам недо определять дополнительные переменые
для передачи данных в функцию.
Декомпозиция
Последнее обновление: 09.04.2018
99
Декомпозиция (destructuring) позволяет извлечь из объекта отдельные значения в
переменные:
1 let user = {
2 name: "Tom",
3 age: 24,
4 phone: "+367438787",
5 email: "tom@[Link]"
6 };
7 let {name, email} = user;
[Link](name); // Tom
8
[Link](email); // tom@[Link]
9
Для декомпозиции объекта переменные помещаются в фигурные скобки и им
присваивается объект. Сопоставление между свойствами объекта и переменными
идет по имени.
Мы можем указать, что мы хотим получить значения свойств объекта в переменные с
другим именем:
1 let user = {
2 name: "Tom",
3 age: 24,
4 phone: "+367438787",
5 email: "tom@[Link]"
6 };
7 let {name: userName, email: mailAddress} = user;
[Link](userName); // Tom
8
[Link](mailAddress); // tom@[Link]
9
100
В данном случае свойство name сопоставляется с переменной userName, а поле email -
с переменной mailAddress.
Декомпозиция массивов
Также можно декомпозировать массивы:
1 let users = ["Tom", "Sam", "Bob"];
2 let [a, b, c] = users;
3
4 [Link](a); // Tom
5 [Link](b); // Sam
6 [Link](c); // Bob
Для декомпозиции массива переменные помещаются в квадратные скобки и
последовательно получают значения элементов массива.
При эом мы можем пропустить ряд элементов массива, оставив вместо имен
переменных пропуски:
1 let users = ["Tom", "Sam", "Bob", "Ann", "Alice", "Kate"];
2 let [first,,,,fifth] = users;
3
4 [Link](first); // Tom
5 [Link](fifth); // Alice
Выражение first,,,,fifth указывает, что мы хотим получить первый элемент
массива в переменную first, затем пропустить три элемента и получить пятый элемент
в переменную fifth.
Подобным образом можно получить, например, второй и четвертый элементы:
1 let users = ["Tom", "Sam", "Bob", "Ann", "Alice", "Kate"];
2 let [,second,,forth] = users;
3
4 [Link](second); // Sam
5 [Link](forth); // Ann
101
Можно совместить получение данных из массива и объекта:
1 let people = [
2 {name: "Tom", age: 34},
3 {name: "Bob", age: 23},
4 {name: "Sam", age: 32}
5 ];
6 let [,{name}] = people;
7
[Link](name); // Bob
8
В данном случае получаем значение свойства name второго объекта в массиве.
Декомпозиция параметров
Если в функцию в качестве параметра передается массив или объект, то его также
можно подобным образом декомпозировать:
1 function display({name:userName, age:userAge}){
2 [Link](userName, userAge);
3 }
4 function sum([a, b, c]){
5 var result = a + b + c;
6 [Link](result);
7 }
8 let user = {name:"Alice", age:33, email: "alice@[Link]"};
9
10
let numbers = [3, 5, 7, 8];
11
12
display(user); // Alice 33
13
sum(numbers); // 15
14
Классы
102
Последнее обновление: 11.04.2018
С внедреием стандарта ES2015 (ES6) в JavaScript появился новый способ определения
объектов - с помощью классов. Класс представляет описание объекта, его состояния и
поведения, а объект является конкретным воплощением или экземпляром класса.
Для определения класса используется ключевое слово class:
1 class Person{
2 }
После слова class идет название класса (в данном случае класс называется Person), и
затем в фигурных скобках определяется тело класса.
Также можно определить анонимный класс и присвоить его переменной:
1 let Person = class{}
После этого мы можем создать объекты класса с помощью конструктора:
1 class Person{}
2
3 let tom = new Person();
4 let bob = new Person();
Для создания объекта с помощью конструктора сначала ставится ключевое
слово new. Затем собственно идет вызов конструктора - по сути вызов функции по
имени класса. По умолчанию классы имеют один конструктор без параметров.
Поэтому в данном случае при вызове конструктора в него не передается никаких
аргументов.
Также мы можем определить в классе свои конструкторы. Также класс может
содержать свойства и методы:
1 class Person{
103
2 constructor(name, age){
3 [Link] = name;
4 [Link] = age;
5 }
6 display(){
7 [Link]([Link], [Link]);
8 }
9 }
10
let tom = new Person("Tom", 34);
11
[Link](); // Tom 34
12
[Link]([Link]); // Tom
13
Конструктор определяется с помощью метода с именем constructor. По сути это
обычный метод, который может принимать параметры. Основная цель конструктора -
инициализировать объект начальными данными. И в данном случае в конструктор
передаются два значения - для имени и возраста пользователя.
Для хранения состояния в классе определяются свойства. Для их определения
используется ключевое слово this. В данном случае в классе два свойства: name и
age.
Поведение класса определяют методы. В данном случае определен метод display(),
который выводит значения свойств на консоль.
Поскольку мы определили конструктор, который принимает два параметра, то
соответственно мы можем передать в конструктор два значения для инициализации
объекта: new Person("Tom", 34).
Наследование
Одни классы могут наследоваться от других. Наследование позволяет сократить
объем кода в классах-наследниках. Например, определим следеющие классы:
1 class Person{
2 constructor(name, age){
3 [Link] = name;
[Link] = age;
4
104
5
}
6
display(){
7
[Link]([Link], [Link]);
8
}
9
}
10
class Employee extends Person{
11 constructor(name, age, company){
12 super(name, age);
13 [Link] = company;
14 }
15 display(){
16 [Link]();
17 [Link]("Employee in", [Link]);
18 }
work(){
19
[Link]([Link], "is hard working");
20
}
21
}
22
23
let tom = new Person("Tom", 34);
24
let bob = new Employee("Bob", 36, "Google");
25
[Link]();
26
[Link]();
27
[Link]();
28
Для наследования одного класса от другого в определении класса применяется
оператор extends, после которого идет название базового класса. То есть в данном
случае класс Employee наследуется от класса Person. Класс Person еще называется
базовым классом, классом-родителем, суперклассом, а класс Employee - классом-
наследником, подклассом, производным классом.
Производный класс, как и базовый, может определять конструкторы, свойства,
методы. Вместе с тем с помощью слова super производный класс может ссылаться на
105
функционал, определенный в базовом. Например, в конструкторе Employee можно
вручную не устанавливать свойства name и age, а с помощью выражения super(name,
age); вызвать конструктор базового класса и тем самым передать работу по
установке этих свойств базовому классу.
Подобным образом в методе display в классе Employee через
вызов [Link]() можно обратиться к реализации метода display класса Person.
Консольный вывод программы:
Tom 34
Bob 36
Employee in Google
Bob is hard working
Статические методы
Статические методы вызываются для всего класса вцелом, а не для отедельного
объекта. Для их определения применяется оператор static. Например:
1
class Person{
2
constructor(name, age){
3 [Link] = name;
4 [Link] = age;
5 }
6 static nameToUpper(person){
7 return [Link]();
8 }
9 display(){
10 [Link]([Link], [Link]);
}
11
}
12
let tom = new Person("Tom Soyer", 34);
13
let personName = [Link](tom);
14
[Link](personName); // TOM SOYER
15
В данном случае определен статический метод nameToUpper(). В качестве параметра
он принимает объект Person и переводит его имя в верхний регистр. Поскольку
106
статический метод относится классу вцелом, а не к объекту, то мы НЕ можем
использовать в нем ключевое слово this и через него обращаться к свойствам объекта.
Встроенные объекты
Последнее обновление: 1.11.2015
Кроме возможности создавать свои объекты JavaScript также предоставляет набор
встроенных типов объектов, которые мы можем применять в различных ситуациях.
Объект Date. Работа с датами
Объект Date позволяет работать с датами и временем в JavaScript.
Существуют различные способы создания объекта Date. Первый способ заключается в
использовании пустого конструктора без параметров:
1 var currentDate = new Date();
2 [Link](currentDate);
В этом случае объект будет указывать на текущую дату компьютера:
Второй способ заключается в передаче в конструктор Date количества миллисекунд,
которые прошли с начала эпохи Unix, то есть с 1 января 1970 года 00:00:00 GMT:
1 var myDate = new Date(1359270000000);
2 [Link](myDate); // Sun Jan 27 2013 10:00:00 GMT+0300 (RTZ 2 (зима))
Третий способ состоит в передаче в конструктор Date дня, месяца и года:
1 var myDate = new Date("27 March 2008");
2 // или так
// var myDate = new Date("3/27/2008");
107
3
[Link](myDate); // Thu Mar 27 2008 00:00:00 GMT+0300 (RTZ 2 (зима))
4
Если мы используем полное название месяца, то оно пишется в по-английски, если
используем сокращенный вариант, тогда используется формат месяц/день/год.
Четвертый способ состоит в передаче в конструктор Date всех параметров даты и
времени:
var myDate = new Date(2012,11,25,18,30,20,10); // Tue Dec 25 2012 18:30:20 GMT+0300
1 (зима))
В данном случае используются по порядку следующие параметры: new Date(год,
месяц, число, час, минуты, секунды, миллисекунды). При этом надо учитывать, что
отсчет месяцев начинается с нуля, то есть январь - 0, а декабрь - 11.
Получение даты и времени
Для получения различных компонентов даты применяется ряд методов:
getDate(): возвращает день месяца
getDay(): возвращает день недели (отсчет начинается с 0 - воскресенье, и
последний день - 6 - суббота)
getMonth(): возвращает номер месяца (отсчет начинается с нуля, то есть
месяц с номер 0 - январь)
getFullYear(): возвращает год
toDateString(): возвращает полную дату в виде строки
getHours(): возвращает час (от 0 до 23)
getMinutes(): возвращает минуты (от 0 до 59)
getSeconds(): возвращает секунды (от 0 до 59)
getMilliseconds(): возвращает миллисекунды (от 0 до 999)
toTimeString(): возвращает полное время в виде строки
Получим текущую дату:
1 var days = ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница"
"Суббота"];
108
2 var months = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
3 "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"];
4
5 var myDate = new Date();
6 var fullDate = "Сегодня: " + [Link]() + " " + months[[Link]()] +
7 " " + [Link]() + ", " + days[[Link]()];
8 [Link](fullDate); // Сегодня: 18 Август 2015, Вторник
Перевести из числовых значений в более привычные названия для дней недели и
месяцев используются массивы. Получив индекс дня недели ([Link]()) и
индекс месяца ([Link]()) можно получить нужный элемент из массива.
Теперь получим текущее время:
1 var welcome;
2 var myDate = new Date();
3 var hour = [Link]();
var minute = [Link]();
4
var second = [Link]();
5
if (minute < 10) {
6
minute = "0" + minute;
7
}
8
if (second < 10) {
9
second = "0" + second;
10
}
11 if (hour < 12) {
12 welcome = "Доброе утро";
13 } else if (hour < 17) {
14 welcome = "Добрый день";
15 } else {
16 welcome = "Добрый вечер";
17 }
18 [Link](welcome + ", текущее время: " + hour +
109
19 ":" + minute + ":" + second); // Добрый вечер, текущее время:
22:50:39
20
Установка даты и времени
Коме задания параметров даты в конструкторе для установки мы также можем
использовать дополнительные методы объекта Date:
setDate(): установка дня в дате
setMonth(): уставовка месяца (отсчет начинается с нуля, то есть месяц с
номер 0 - январь)
setFullYear(): устанавливает год
setHours(): установка часа
setMinutes(): установка минут
setSeconds(): установка секунд
setMilliseconds(): установка миллисекунд
Установим дату:
1 var days = ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четвег", "Пятница"
"Суббота"];
2
var months = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
3
"Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"];
4
5
var myDate = new Date();
6
[Link](15);
7 [Link](6);
8 [Link](2013);
9
10 var fullDate = [Link]() + " " + months[[Link]()] +
11 " " + [Link]() + ", " + days[[Link]()];
12 [Link](fullDate); // 15 Июль 2013, Понедельник
При установке значений мы можем передать величину, большую, чем максимальное
допустимое значение. Например, установить для часа число 54:
110
1 [Link](54);
В этом случае значение часа будет равно 54 - 24 * 2 = 6, а оставшиеся часы будут
составлять два дня (24 * 2), что прибавит к дате два дня. То же самое действует и в
отношении дней, минут, секунд, миллисекунд и месяцев.
Объект Math. Математические операции
Последнее обновление: 1.11.2015
Объект Math предоставляет ряд математических функций, которые можно
использовать при вычислениях. Рассмотрим основные математические функции.
abs()
Функция abs() возвращает абсолютное значение числа:
1 var x = -25;
2 [Link]([Link](x)); // 25
3 var y = 34;
4 [Link]([Link](y)); // 34
min() и max()
Функции min() и max() возвращают соответственно минимальное и максимальное
значение из набора чисел:
1 var max = [Link](19, 45); // 45
2 var min = [Link](33, 24); // 24
Эти функции необязательно должны принимать два числа, в них можно передавать и
большее количество чисел:
1 var max = [Link](1, 2, 3, -9, 46, -23); // 46
111
ceil()
Функция ceil() округляет число до следующего наибольшего целого числа:
1 var x = [Link](9.2); // 10
2 var y = [Link](-5.9); // -5
Выражение [Link](9.2) возвращает число 10, так как число 10 следующее
наибольшее целое число после 9.2. И также выражение [Link](-5.9) возвращает -
5, потому что число -5 следующее наибольшее целое после -5.9
floor()
Функция floor() округляет число до следующего наименьшего целого числа:
1 var x = [Link](9.2); // 9
2 var y = [Link](-5.9); // -6
round()
Функция round() округляет число до следующего наименьшего целого числа, если
его десятичная часть меньше 0.5. Если же десятичная часть равна или больше 0.5, то
округление идет до ближайшего наибольшего целого числа:
1 var x = [Link](5.5); // 6
2 var y = [Link](5.4); // 5
3 var z = [Link](-5.4); // -5
4 var n = [Link](-5.5); // -5
5 var m = [Link](-5.6); // -6
6 [Link](x);
7 [Link](y);
[Link](z);
8
[Link](n);
9
random()
Функция random() возвращает случайное число с плавающей точкой их диапазона от
0 до 1:
1 var x = [Link]();
112
pow()
Функция pow() возвращает число в определенной степени. Например, возведем число
2 в степень 3:
1 var x = [Link](2, 3); // 8
sqrt()
Функция sqrt() возвращает квадратный корень числа:
1 var x = [Link](121); // 11
2 var y = [Link](9); // 3
3 var z = [Link](20); // 4.47213595499958
log()
Функция log() возвращает натуральный логарифм числа:
1 var x = [Link](1); // 0
2 var z = [Link](10); // 2.302585092994046
Тригонометрические функции
Целый ряд функций представляют тригонометрические функции: sin() (вычисляет
синус угла), cos() (вычисляет косинус угла), tan() (вычисляет тангенс угла). В
качестве значения они приимают значение в радианах.
1 var x = [Link]([Link]/2); // 1
2 var y = [Link](0); // 1
3 var z = [Link]([Link]/4); // 0.9999999999999999
4 var s = [Link]([Link]/4); // 0.7071067811865476
5 var c = [Link]([Link]/4); // 0.7071067811865476
6 [Link](x, y, z, s, c);
Функция asin() вычисляет арксинус числа, acos - арккосинус, а atan() - арктангенс
числа:
1 var x = [Link](0.9); // 1.1197695149986342
2 var y = [Link](1); // 1
3 var z = [Link](1); // 0.7853981633974483
113
Константы
Кроме методов объект Math также определяет набор встроенных констант, которые
можно использовать в различных вычислениях:
[Link] (число PI): 3.141592653589793
Math.SQRT2 (квадратный корень из двух): 1.4142135623730951
Math.SQRT1_2 (половина от квадратного корня из двух): 0.7071067811865476
Math.E (число e или число Эйлера): 2.718281828459045
Math.LN2 (натуральный логарифм числа 2): 0.6931471805599453
Math.LN10 (натуральный логарифм числа 10): 2.302585092994046
Math.LOG2E (двоичный логарифм числа e): 1.4426950408889634
Math.LOG10E (десятичный логарифм числа e): 0.4342944819032518
Используем константы в вычислениях:
1 var x = [Link](Math.E); // 1
2 var z = [Link]([Link]/4); // 0.9999999999999999
Объект Array. Работа с массивами
Последнее обновление: 26.03.2018
Объект Array представляет массив и предоставляет ряд свойств и методов, с
помощью которых мы можем управлять массивом.
Инициализация массива
Можно создать пустой массив, используя квадратные скобки или конструктор Array:
1 var users = new Array();
114
2 var people = [];
3
4 [Link](users); // Array[0]
5 [Link](people); // Array[0]
Можно сразу же инициализировать массив некоторым количеством элементов:
1 var users = new Array("Tom", "Bill", "Alice");
2 var people = ["Sam", "John", "Kate"];
3
4 [Link](users); // ["Tom", "Bill", "Alice"]
5 [Link](people); // ["Sam", "John", "Kate"]
Можно определить массив и по ходу определять в него новые элементы:
1 var users = new Array();
2 users[1] = "Tom";
3 users[2] = "Kate";
4 [Link](users[1]); // "Tom"
5 [Link](users[0]); // undefined
При этом не важно, что по умолчанию массив создается с нулевой длиной. С помощью
индексов мы можем подставить на конкретный индекс в массиве тот или иной
элемент.
length
Чтобы узнать длину массива, используется свойство length:
1 var fruit = new Array();
2 fruit[0] = "яблоки";
3 fruit[1] = "груши";
fruit[2] = "сливы";
4
5
[Link]("В массиве fruit " + [Link] + " элемента: <br/>");
6
115
7 for(var i=0; i < [Link]; i++)
8 [Link](fruit[i]);
По факту длиной массива будет индекс последнего элемента с добавлением единицы.
Например:
1 var users = new Array(); // в массиве 0 элементов
2 users[0] = "Tom";
3 users[1] = "Kate";
4 users[4] = "Sam";
5 for(var i=0; i<[Link];i++)
6 [Link](users[i]);
Вывод браузера:
Tom
Kate
undefined
undefined
Sam
Несмотря на то, что для индексов 2 и 3 мы не добавляли элементов, но длиной
массива в данном случае будет число 5. Просто элементы с индексами 2 и 3 будут
иметь значение undefined.
Копирование массива. slice()
Копирование массива может быть поверхностным или неглубоким (shallow copy) и
глубоким (deep copy).
При неглубоком копировании достаточно присвоить переменной значение другой
переменной, которая хранит массив:
1 var users = ["Tom", "Sam", "Bill"];
2 [Link](users); // ["Tom", "Sam", "Bill"]
3 var people = users; // неглубокое копирование
4
people[1] = "Mike"; // изменяем второй элемент
5
116
6 [Link](users); // ["Tom", "Mike", "Bill"]
В данном случае переменная people после копирования будет указывать на тот же
массив, что и переменная users. Поэтому при изменении элементов в people,
изменятся элементы и в users, так как фактически это один и тот же массив.
Такое поведение не всегда является желательным. Например, мы хотим, чтобы после
копирования переменные указывали на отдельные массивы. И в этом случае можно
использовать глубокое копирование с помощью метода slice():
1 var users = ["Tom", "Sam", "Bill"];
2 [Link](users); // ["Tom", "Sam", "Bill"]
3 var people = [Link](); // глубокое копирование
4
5 people[1] = "Mike"; // изменяем второй элемент
6 [Link](users); // ["Tom", "Sam", "Bill"]
7 [Link](people); // ["Tom", "Mike", "Bill"]
В данном случае после копирования переменные будут указывать на разные массивы,
и мы сможем изменять их отдельно друг от друга.
Также метод slice() позволяет скопировать часть массива:
1 var users = ["Tom", "Sam", "Bill", "Alice", "Kate"];
2 var people = [Link](1, 4);
3 [Link](people); // ["Sam", "Bill", "Alice"]
В метод slice() передается начальный и конечный индексы, которые используются
для выборки значений из массива. То есть в данном случае выборка в новый массив
идет начиная с 1 индекса по индекс 4 не включая. И поскольку индексация массивов
начинается с нуля, то в новом массиве окажутся второй, третий и четвертый элемент.
push()
Метод push() добавляет элемент в конец массива:
1 var fruit = [];
2 [Link]("яблоки");
3 [Link]("груши");
117
4 [Link]("сливы");
5 [Link]("вишня","абрикос");
6
7 [Link]("В массиве fruit " + [Link] + " элемента: <br/>");
8 [Link](fruit); // яблоки,груши,сливы,вишня,абрикос
pop()
Метод pop() удаляет последний элемент из массива:
1 var fruit = ["яблоки", "груши", "сливы"];
2
3 var lastFruit = [Link](); // извлекаем из массива последний элемент
4 [Link](lastFruit );
5 [Link]("В массиве fruit " + [Link] + " элемента: <br/>");
6 for(var i=0; i <[Link]; i++)
7 [Link](fruit[i] );
Вывод браузера:
сливы
В массиве fruit 2 элемента:
яблоки
груши
shift()
Метод shift() извлекает и удаляет первый элемент из массива:
1 var fruit = ["яблоки", "груши", "сливы"];
2
3 var firstFruit = [Link]();
4 [Link](firstFruit );
5 [Link]("В массиве fruit " + [Link] + " элемента: <br/>");
6 for(var i=0; i <[Link]; i++)
7 [Link](fruit[i] );
118
Вывод браузера:
яблоки
В массиве fruit 2 элемента:
груши
сливы
unshift()
Метод unshift() добавляет новый элемент в начало массива:
1 var fruit = ["яблоки", "груши", "сливы"];
2 [Link]("абрикосы");
3 [Link](fruit);
Вывод браузера:
абрикосы,яблоки,груши,сливы
Удаление элемента по индексу. splice()
Метод splice() удаляет элементы с определенного индекса. Например, удаление
элементов с третьего индекса:
1 var users = ["Tom", "Sam", "Bill", "Alice", "Kate"];
2 var deleted = [Link](3);
3 [Link](deleted); // [ "Alice", "Kate" ]
4 [Link](users); // [ "Tom", "Sam", "Bill" ]
Метод splice возвращает удаленные элементы.
В данном случае удаление идет с начала массива. Если передать отрицательный
индекс, то удаление будет производиться с конца массива. Например, удалим
последний элемент:
1 var users = ["Tom", "Sam", "Bill", "Alice", "Kate"];
2 var deleted = [Link](-1);
3 [Link](deleted); // [ "Kate" ]
4 [Link](users); // [ "Tom", "Sam", "Bill", "Alice" ]
119
Дополнительная версия метода позволяет задать количество элементов для
удаления. Например, удалим с первого индекса три элемента:
1 var users = ["Tom", "Sam", "Bill", "Alice", "Kate"];
2 var deleted = [Link](1,3);
3 [Link](deleted); // [ "Sam", "Bill", "Alice" ]
4 [Link](users); // [ "Tom", "Kate" ]
Еще одна версия метода splice позволяет вставить вместо удаляемых элементов
новые элементы:
1 var users = ["Tom", "Sam", "Bill", "Alice", "Kate"];
2 var deleted = [Link](1,3, "Ann", "Bob");
3 [Link](deleted); // [ "Sam", "Bill", "Alice" ]
4 [Link](users); // [ "Tom", "Ann", "Bob", "Kate" ]
В данном случае удаляем три элемента с 1-го индекса и вместо них вставляем два
элемента.
concat()
Метод concat() служит для объединения массивов:
1 var fruit = ["яблоки", "груши", "сливы"];
2 var vegetables = ["помидоры", "огурцы", "картофель"];
3 var products = [Link](vegetables);
4
5 for(var i=0; i < [Link]; i++)
6 [Link](products[i] );
При этом необязательно объединять только однотипные массивы. Можно и
разнотипные:
1 var fruit = ["яблоки", "груши", "сливы"];
2 var prices = [20, 30, 80];
3 var products = [Link](prices);
120
join()
Метод join() объединяет все элементы массива в одну строку:
1 var fruit = ["яблоки", "груши", "сливы", "абрикосы", "персики"];
2 var fruitString = [Link](", ");
3 [Link](fruitString);
В метод join() передается разделитель между элементами массива. В данном случае
в качестве разделителя будет использоваться запятая и пробел (", ").
sort()
Метод sort() сортирует массив по возрастанию:
1 var fruit = ["яблоки", "груши", "сливы", "абрикосы", "персики"];
2 [Link]();
3
4 for(var i=0; i < [Link]; i++)
5 [Link](fruit[i] );
Вывод в браузере:
абрикосы
груши
персики
сливы
яблоки
reverse()
Метод reverse() переворачивает массив задом наперед:
1 var fruit = ["яблоки", "груши", "сливы", "абрикосы", "персики"];
2 [Link]();
3
4 for(var i=0; i < [Link]; i++)
5 [Link](fruit[i] );
121
Вывод в браузере:
персики
абрикосы
сливы
груши
яблоки
В сочетании с методом sort() можно отсортировать массив по убыванию:
1 var fruit = ["яблоки", "груши", "сливы", "абрикосы", "персики"];
2 [Link]().reverse();
3
4 for(var i=0; i < [Link]; i++)
5 [Link](fruit[i] );
Вывод в браузере:
яблоки
сливы
персики
груши
абрикосы
Поиск индекса элемента
Методы indexOf() и lastIndexOf() возвращают индекс первого и последнего
включения элемента в массиве. Например:
1 var fruit = ["яблоки", "груши", "сливы", "яблоки", "груши"];
2
3 var firstIndex = [Link]("яблоки");
4 var lastIndex = [Link]("яблоки");
5 var otherIndex = [Link]("вишни");
6 [Link](firstIndex); // 0
7 [Link](lastIndex); // 3
[Link](otherIndex); // -1
8
122
firstIndex имеет значение 0, так как первое включение стоки "яблоки" в массиве
приходится на индекс 0, а последнее на индекс 3.
Если же элемент отсутствует в массиве, то в этом случае
методы indexOf() и lastIndexOf() возвращают значение -1.
every()
Метод every() проверяет, все ли элементы соответствуют определенному условию:
1 var numbers = [ 1, -12, 8, -4, 25, 42 ];
2 function condition(value, index, array) {
3 var result = false;
4 if (value > 0) {
5 result = true;
6 }
7 return result;
8 };
var passed = [Link](condition);
9
[Link](passed); // false
10
В метод every() в качестве параметра передается функция, представляющая
условие. Эта функция принимает три параметра:
1 function condition(value, index, array) {
2
3 }
Параметр value представляет текущий перебираемый элемент массива,
параметр index представляет индекс этого элемента, а параметр array передает
ссылку на массив.
В этой функции мы можем проверить переданное значение элемента на соответствие
какому-нибудь условию. Например, в данном примере мы проверяем каждый элемент
массива, больше ли он нуля. Если больше, то возвращаем значение true, то есть
элемент соответствует условию. Если меньше, то возвращаем false - элемент не
соответствует условию.
123
В итоге, когда происходит вызов метода [Link](condition) он перебирает все
элементы массива numbers и по очереди передает их в функцию condition. Если эта
функция возвращает значение true для всех элементов, то и
метод every() возвращает true. Если хотя бы один элемент не соответствует
условию, то метод every() возвращает значение false.
some()
Метод some() похож на метод every(), только он проверяет, соответствует ли хотя бы
один элемент условию. И в этом случае метод some() возвращает true. Если
элементов, соответствующих условию, в массиве нет, то возвращается
значение false:
1 var numbers = [ 1, -12, 8, -4, 25, 42 ];
2 function condition(value) {
3 var result = false;
4 if (value === 8) {
5 result = true;
6 }
7 return result;
};
8
var passed = [Link](condition); // true
9
В данном случае мы используем только один параметр функции condition - value,
через который получаем поочередно элементы массива.
filter()
Метод filter(), как some() и every(), принимает функцию условия. Но при этом
возвращает массив тех элементов, которые соответствуют этому условию:
1 var numbers = [ 1, -12, 8, -4, 25, 42 ];
2 function condition(value) {
3 var result = false;
if (value > 0) {
4
result = true;
5
}
6
return result;
7
124
8 };
9 var filteredNumbers = [Link](condition);
10
11 for(var i=0; i < [Link]; i++)
12 [Link](filteredNumbers[i] );
Вывод в браузере:
25
42
forEach() и map()
Методы forEach() и map() осуществляют перебор элементов и выполняют с ними
определенный операции. Например, для вычисления квадратов чисел в массиве
можно использовать следующий код:
1 var numbers = [ 1, 2, 3, 4, 5, 6];
2 for(var i = 0; i<[Link]; i++){
3
4 var result = numbers[i] * numbers[i];
5
6 [Link]("Квадрат числа " + numbers[i] + " равен " + result );
7 }
Но с помощью метода forEach() можно упростить эту конструкцию:
1 var numbers = [ 1, 2, 3, 4, 5, 6];
2
3 function square(value) {
4
5 var result = value * value;
[Link]("Квадрат числа " + value + " равен " + result );
6
};
7
125
8
9 [Link](square);
Метод forEach() в качестве параметра принимает все ту же функцию, в которую при
переборе элементов передается текущий перебираемый элемент и над ним
выполняются операции.
Метод map() похож на метод forEach, он также в качестве параметра принимает
функцию, с помощью которой выполняются операции над перебираемыми
элементами массива, но при этом метод map() возвращает новый массив с
результатами операций над элементами массива.
Например, применим метод map к вычислению квадратов чисел массива:
1 var numbers = [ 1, 2, 3, 4, 5, 6];
2
3 function square(value) {
4
5 return result = value * value;
6 };
7
8 var squareArray = [Link](square);
9 [Link](squareArray);
Функция, которая передается в метод map() получает текущий перебираемый
элемент, выполняет над ним операции и возвращает некоторое значение. Это
значение затем попадает в результирующий массив squareArray
Объект Number
Последнее обновление: 1.11.2015
Объект Number представляет числа. Чтобы создать число, надо передать в
конструктор Number число или стоку, представляющую число:
126
1 var x = new Number(34);
2 var y = new Number('34');
3 [Link](x+y); // 68
Определения x и y в данном случае будут практически аналогичны.
Однако создавать объект Number можно и просто присвоив переменной определенное
число:
1 var z = 34;
Объект Number предоставляет ряд свойств и методов. Некоторые его свойства:
Number.MAX_VALUE: наибольшее возможное число. Приблизительно равно
1.79E+308. Числа, которые больше этого значения, рассматриваются как Infinity
Number.MIN_VALUE: наименьшее возможное положительное число.
Приблизительно равно 5e-324 (где-то около нуля)
[Link]: специальное значение, которое указывает, что объект не является
числом
Number.NEGATIVE_INFINITY: значение, которое обозначает отрицательную
неопределенность и которое возникает при переполнении. Например, если мы
складываем два отрицательных числа, которые по модулю равны
Number.MAX_VALUE. Например:
1 var x = -1 * Number.MAX_VALUE
2 var y = -1 * Number.MAX_VALUE
3 var z = x + y;
4 if(z===Number.NEGATIVE_INFINITY)
5 [Link]("отрицательная неопределенность");
6 else
7 [Link](z);
Number.POSITIVE_INFINITY: положительная неопределенность. Также, как и
отрицательная неопределенность, возникает при переполнении, только теперь
в положительную сторону:
1 var x = Number.MAX_VALUE
2 var y = Number.MAX_VALUE
3 var z = x * y;
4 if(z===Number.POSITIVE_INFINITY)
5 [Link]("положительная неопределенность");
6 else
7 [Link](z);
Некоторые основные методы:
isNaN(): определяет, является ли объект числом. Если объект не является
числом, то возвращается значение true:
127
1 var a = [Link]([Link]); // true
2 var b = [Link](true); // false - new Number(true) = 1
3 var c = [Link](null); // false - new Number(null) = 0
4 var d = [Link](25); // false
5 var e = [Link]("54"); // false
Но следующее выражение вернет false, хотя значение не является числом:
1 var f = [Link]("hello"); // false
Чтобы избежать подобных ситуаций, лучше применять глобальную
функцию isNaN:
1 var f = isNaN("hello"); // true
parseFloat(): преобразует строку в число с плавающей точкой. Например:
1 var a = [Link]("34.90"); // 34.9
2 [Link](a);
3 var b = [Link]("hello"); // NaN
4 [Link](b);
5 var c = [Link]("34hello"); // 34
6 [Link](c);
parseInt(): преобразует строку в целое число. Например:
1 var a = [Link]("34.90"); // 34
2 [Link](a);
3 var b = [Link]("hello"); // NaN
4 [Link](b);
5 var c = [Link]("25hello"); // 25
6 [Link](c);
toFixed(): оставляет в числе с плавающей точкой определенное количество
знаков в дробной части. Например:
1 var a = 10 / 1.44;
2 [Link]("До метода toFixed(): " + a + "<br/>");
3 a = [Link](2); // оставляем два знака после запятой
4 [Link]("После метода toFixed(): " + a + "<br/>");
Вывод браузера:
До метода toFixed(): 6.944444444444445
После метода toFixed(): 6.94
Строки
128
Строки и объект String
Последнее обновление: 06.04.2018
Для создания строк мы можем как напрямую присваивать переменной строку:
1 let name = "Tom";
Для работы со строками предназначен объект String, поэтому также можно
использовать конструктор String:
1 var name = new String("Tom");
Но как правило, используется первый более краткий способ. В первом случае
JavaScript при необходимости автоматически преобразует переменную примитивного
типа в объект String.
Объект String имеет большой набор свойств и методов, с помощью которых мы можем
манипулировать строками.
Свойство length указывает на длину строки:
1 var hello = "привет мир";
2 [Link]("В строке '" + hello + "' " + [Link] + " символов");
Метод repeat() позволяет создать строку путем многократного повторения другой
строки. Количество повторов передается в качестве аргумента:
1 let hello = "hello ";
2 [Link]([Link](3)); // hello hello hello
Шаблоны строк
Шаблоны строк позволяют вставлять в строку различные значения. Для этого строки
заключаются в косые кавычки:
1 let name = "Tom";
129
2 let hello = `Hello ${name}`;
3 [Link](hello); // Hello Tom
4
5 let age = 23;
6 let info = `${name} is ${age} years old`;
7 [Link](info); // Tom is 23 years old
Для вставки значения в строку оно заключается в фигурные скобки, перед которыми
ставится знак доллара.
Также вместо скалярных значений могут добавляться свойства сложных объектов или
результаты выражений:
1
let tom ={
2 name: "Tom",
3 age: 25
4 }
5 let info = `${[Link]} is ${[Link]} years old`;
6 [Link](info); // Tom is 23 years old
7
8 function sum(x, y){
9 return x + y;
10 }
let a = 5, b = 4;
11
let result = `${a} + ${b} = ${sum(a, b)}`;
12
[Link](result); // 5 + 4 = 9
13
Поиск в строке
Для поиска в строки некоторой подстроки используются методы indexOf() (индекс
первого вхождения подстроки) и lastIndexOf() (индекс последнего вхождения
подстроки). Эти методы принимают два параметра:
Подстроку, которую надо найти
Необязательный параметр, который указывает, с какого символа следует
проводить поиск подстроки в строке
130
Оба этих метода возвращают индекс символа, с которого в строке начинается
подстрока. Если подстрока не найдена, то возвращается число -1.
1 let hello = "привет мир. пока мир";
2 let key = "мир";
3 let firstPos = [Link](key);
4 let lastPos = [Link](key);
5 [Link]("Первое вхождение: ", firstPos); // 7
6 [Link]("Последнее вхождение: ", lastPos); // 17
Еще один метод - includes() возвращает true, если строка содержит определенную
подстроку.
1 let hello = "привет мир. пока мир";
2
3 [Link]([Link]("мир")); // true
4 [Link]([Link]("миг")); // false
С помощью второго дополнительного параметра можно определить индекс, с
которого будет начинаться поиск подстроки:
1 let hello = "привет мир. пока мир";
2
3 [Link]([Link]("мир", 5)); // true
4 [Link]([Link]("привет", 6)); // false
Выбор подстроки
Для того, чтобы вырезать из строки подстроку, применяются
методы substr() и substring().
Метод substring() принимает два параметра:
индекс символа в строке, начиная с которого надо проводить обрезку строки
индекс, до которого надо обрезать строку
1 let hello = "привет мир. пока мир";
2 let world = [Link](7, 10); // с 7-го по 10-й индекс
131
3 [Link](world); // мир
Метод substr() также в качестве первого параметра принимает начальный индекс
подстроки, а в качестве второго - длину вырезаемой подстроки:
1 let hello = "привет мир. пока мир";
2 let bye = [Link](12, 4);
3 [Link](bye); // пока
Если второй параметр не указывается, то обрезается вся остальная часть строки:
1 let hello = "привет мир. пока мир";
2 let bye = [Link](12);
3 [Link](bye); // пока мир
Управление регистром
Для изменения регистра имеются методы toLowerCase() (для перевода в нижний
регистр) и toUpperCase() (для перевода в верхний регистр).
1 let hello = "Привет Том";
2 [Link]([Link]()); // привет том
3 [Link]([Link]()); // ПРИВЕТ ТОМ
Получение символа по индексу
Чтобы получить определенный символ в строке по индексу, можно применять
методы charAt() и charCodeAt(). Оба этих метода в качестве параметра принимают
индекс символа:
1 let hello = "Привет Том";
2 [Link]([Link](2)); // и
3 [Link]([Link](2)); // 1080
Но если в качестве результата метод charAt() возвращает сам символ, то
метод charCodeAt() возвращает числовой код этого символа.
Удаление пробелов
Для удаления начальных и концевых пробелов в стоке используется метод trim():
132
1 let hello = " Привет Том ";
2 let beforeLength = [Link];
3 hello = [Link]();
4 let afterLength = [Link];
5 [Link]("Длина строки до: ", beforeLength); // 15
6 [Link]("Длина строки после: ", afterLength); // 10
Объединение строк
Метод concat() объединяет две строки:
1 let hello = "Привет ";
2 let world = "мир";
3 hello = [Link](world);
4 [Link](hello); // Привет мир
Замена подстроки
Метод replace() заменяет первое вхождение одной подстроки на другую:
1 let hello = "Добрый день";
2 hello = [Link]("день", "вечер");
3 [Link](hello); // Добрый вечер
Первый параметр метода указывает, какую подстроку надо заменить, а второй
параметр - на какую подстроку надо заменить.
Разделение строки
Метод split() разбивает строку на массив подстрок по определенному разделителю. В
качестве разделителя используется строка, которая передается в метод:
1 var message = "Сегодня была прекрасная погода";
2 var stringArray = [Link](" ");
3 for(var str in stringArray)
4 [Link](stringArray[str]);
Вывод браузера
133
Сегодня
была
прекрасная
погода
Проверка начала и окончания строки
Метод startsWith() возвращает true, если строка начинается с определенной
подстроки. А метод endsWith() возвращает true, если строка оканчивается на
определенную подстроку.
1 let hello = "let me speak from my heart";
2 [Link]([Link]("let")); // true
3 [Link]([Link]("Let")); // false
4 [Link]([Link]("lets")); // false
5
6 [Link]([Link]("heart")); // true
7 [Link]([Link]("bart")); // false
При этом играет роль регистр символов, и из примера выше мы видим, что "let" не
эквивалентно "Let".
Дополнительный второй параметр позволяет указать индекс (для startsWith - индекс с
начала, а для endsWith - индекс с конца строки), относительно которого будет
производиться сравнение:
let hello = "let me speak from my heart";
1
[Link]([Link]("me", 4)); // true, "me" - 4 индекс с начала
2 строки
3
4 [Link]([Link]("my", [Link]-8)); // true, "my" - 8 индекс
с конца
Объект RegExp. Регулярные выражения
Последнее обновление: 1.11.2015
134
Регулярные выражения представляют шаблон, который используется для поиска
или модификации строки. Для работы с регулярными выражениями в JavaScript
определен объект RegExp.
Определить регулярное выражение можно двумя способами:
1 var myExp = /hello/;
2 var myExp = new RegExp("hello");
Используемое здесь регулярное выражение довольно простое: оно состоит из одного
слова "hello". В первом случае выражение помещается между двумя косыми чертами,
а во втором случае используется конструктор RegExp, в который выражение
передается в виде строки.
Методы RegExp
Чтобы определить, соответствует ли регулярное выражение строке, в объекте RegExp
определен метод test(). Этот метод возвращает true, если строка соответствует
регулярному выражению, и false, если не соответствует.
1 var initialText = "hello world!";
2 var exp = /hello/;
3 var result = [Link](initialText);
4 [Link](result + "<br/>"); // true
5
6 initialText = "beautifull wheather";
7 result = [Link](initialText);
[Link](result); // false - в строке initialText нет "hello"
8
Аналогично работает метод exec - он также проверяет, соответствует ли строка
регулярному выражению, только теперь данный метод возвращает ту часть строки,
которая соответствует выражению. Если соответствий нет, то возвращается
значение null.
1 var initialText = "hello world!";
2 var exp = /hello/;
135
3 var result = [Link](initialText);
4 [Link](result + "<br/>"); // hello
5
6 initialText = "beautifull wheather";
7 result = [Link](initialText);
8 [Link](result); // null
Группы символов
Регулярное выражение не обязательно состоит из обычных строк, но также может
включать специальные элементы синтаксиса регулярных выражений. Один из таких
элементов представляют группы символов, заключенные в квадратные скобки.
Например:
1 var initialText = "обороноспособность";
2 var exp = /[абв]/;
3 var result = [Link](initialText);
4 [Link](result + "<br/>"); // true
5
6 initialText = "город";
7 result = [Link](initialText);
[Link](result); // false
8
Выражение [абв] указывает на то, что строка должна иметь одну из трех букв.
Если нам надо определить наличие в строке буквенных символов из определенного
диапазона, то можно разу задать этот диапазон:
1 var initialText = "обороноспособность";
2 var exp = /[а-я]/;
3 var result = [Link](initialText);
[Link](result + "<br/>"); // true
4
5
initialText = "3di0789";
6
result = [Link](initialText);
7
[Link](result); // false
136
В данном случае строка должна содержать хотя бы один символ из диапазона а-я.
Если, наоборот, не надо, чтобы строка имела только определенные символы, то
необходимо в квадратных скобках перед перечислением символов ставить знак ^:
1 var initialText = "обороноспособность";
2 var exp = /[^а-я]/;
3 var result = [Link](initialText);
4 [Link](result + "<br/>"); // false
5
6 initialText = "3di0789";
7 exp = /[^0-9]/;
8 result = [Link](initialText);
[Link](result); // true
9
В первом случае строка не должна иметь только символы из диапазона а-я, но
поскольку строка "обороноспособность" состоит только из символов из этого
диапазона, то метод test() возвращает false, то есть регулярное выражение не
соответствует стоке.
Во втором случае ("3di0789") строка не должна состоять только из цифровых
символов. Но так как в строке также есть и буквы, то строка соответствует
регулярному выражению, поэтому метод test возвращает значение true.
При необходимости мы можем собирать комбинации выражений:
1 var initialText = "дома";
2 var exp = /[дт]о[нм]/;
3 var result = [Link](initialText);
4 [Link](result); // true
Выражение [дт]о[нм] указывает на те строки, которые могут содержать подстроки
"дом", "том", "дон", "тон".
137
Свойства выражений
Свойство global позволяет найти все подстроки, которые соответствуют
регулярному выражению. По умолчанию при поиске подстрок регулярное
выражение выбирает первую попавшуюся подстроку из строки, которая
соответствует выражению. Хотя в строке может быть множество подстрок,
которые также соответствуют выражению. Для этого применяется данное
свойство в виде символа g в выражениях
Свойство ignoreCase позволяет найти подстоки, которые соответствуют
регулярному выражению, вне зависимости от регистра символов в строке. Для
этого в регулярных выражениях применяется символ i
Свойство multiline позволяет найти подстроки, которые соответствуют
регулярному выражению, в многострочном тексте. Для этого в регулярных
выражениях применяется символ m
Например:
1 var initialText = "привет Мир";
2 var exp = /мир/;
3 var result = [Link](initialText); // false
Здесь совпадения строки с выражением нет, так как "Мир" отличается от "мир" по
регистру. В этом случае надо изменить регулярное выражение, добавив в него
свойство ignoreCase:
1 var exp = /мир/i;
Ну и также мы можем использовать сразу несколько свойств:
1 var exp = /мир/ig;
Регулярные выражения в методах String
Последнее обновление: 1.11.2015
138
Ряд методов объекта String могут использовать регулярные выражения в качестве
параметра.
Разделение строки. Метод split
Метод split может использовать регулярные выражения для разделения строк.
Например, разделим приложение по словам:
1 var initialText = "Сегодня была прекрасная погода";
2 var exp = /\s/;
3 var result = [Link](exp);
4 [Link](function(value, index, array){
5
6 [Link](value + "<br/>");
7 })
Вывод браузера:
Сегодня
была
прекрасная
погода
Метод match
Для поиска всех соответствий в строке применяется метод match():
1 var initialText = "Он пришел домой и сделал домашнюю работу";
2 var exp = /дом[а-я]*/gi;
3 var result = [Link](exp);
4 [Link](function(value, index, array){
5
6 [Link](value + "<br/>");
7 })
Символ звездочки указывает на возможность наличия после строки "дом"
неопределенного количества символов от а до я. В итоге в массиве result окажутся
следующие слова:
139
домой
домашнюю
Поиск в строке. Метод search
Метод search находит индекс первого включения соответствия в строке:
1 var initialText = "hello world";
2 var exp = /wor/;
3 var result = [Link](exp);
4 [Link](result); // 6
Замена. Метод replace
Метод replace позволяет заменить все соответствия регулярному выражению
определенной строкой:
1 var menu = "Завтрак: каша, чай. Обед: суп, чай. Ужин: салат, чай.";
2 var exp = /чай/gi;
3 menu = [Link](exp, "кофе");
4 [Link](menu);
Вывод браузера:
Завтрак: каша, кофе. Обед: суп, кофе. Ужин: салат, кофе.
Синтаксис регулярных выражений
Последнее обновление: 1.11.2015
Рассмотрим базовые моменты синтаксиса регулярных выражений.
Метасимволы
Регулярные выражения также могут использовать метасимволы - символы, которые
имеют определенный смысл:
140
\d: соответствует любой цифре от 0 до 9
\D: соответствует любому символу, который не является цифрой
\w: соответствует любой букве, цифре или символу подчеркивания (диапазоны
A–Z, a–z, 0–9)
\W: соответствует любому символу, который не является буквой, цифрой или
символом подчеркивания (то есть не находится в следующих диапазонах A–Z,
a–z, 0–9)
\s: соответствует пробелу
\S: соответствует любому символу, который не является пробелом
.: соответствует любому символу
Здесь надо заметить, что метасимвол \w применяется только для букв латинского
алфавита, кириллические символы для него не подходят.
Так, стандартный формат номера телефона +1-234-567-8901 соответствует
регулярному выражению \d-\d\d\d-\d\d\d-\d\d\d\d. Например, заменим числа
номера нулями:
1 var phoneNumber = "+1-234-567-8901";
2 var myExp = /\d-\d\d\d-\d\d\d-\d\d\d\d/;
3 phoneNumber = [Link](myExp, "00000000000");
4 [Link](phoneNumber);
Модификаторы
Кроме выше рассмотренных элементов регулярных выражений есть еще одна группа
комбинаций, которая указывает, как символы в строке будут повторяться. Такие
комбинации еще называют модификаторами:
{n}: соответствует n-ому количеству повторений предыдущего символа.
Например, h{3} соответствует подстроке "hhh"
{n,}: соответствует n и более количеству повторений предыдущего символа.
Например, h{3,} соответствует подстрокам "hhh", "hhhh", "hhhhh" и т.д.
{n,m}: соответствует от n до m повторений предыдущего символа.
Например, h{2, 4} соответствует подстрокам "hh", "hhh", "hhhh".
141
?: соответствует одному вхождению предыдущего символа в подстроку или его
отсутствию в подстроке. Например, /h?ome/ соответствует подстрокам "home"
и "ome".
+: соответствует одному и более повторений предыдущего символа
*: соответствует любому количеству повторений или отсутствию предыдущего
символа
^: соответствует началу строки. Например, ^h соответствует строке "home", но
не "ohma", так как h должен представлять начало строки
$: соответствует концу строки. Например, м$ соответствует строке "дом", так
как строка должна оканчиваться на букву м
Например, возьмем номер тот же телефона. Ему соответствует регулярное
выражение \d-\d\d\d-\d\d\d-\d\d\d\d. Однако с помощью выше рассмотренных
комбинаций мы его можем упростить: \d-\d{3}-\d{3}-\d{4}
Также надо отметить, что так как символы ?, +, * имеют особый смысл в регулярных
выражениях, то чтобы их использовать в обычным для них значении (например, нам
надо заменить знак плюс в строке на минус), то данные символы надо экранировать с
помощью слеша:
1 var phoneNumber = "+1-234-567-8901";
2 var myExp = /\+\d-\d{3}-\d{3}-\d{4}/;
3 phoneNumber = [Link](myExp, "80000000000");
4 [Link](phoneNumber);
Отдельно рассмотрим применение комбинации '\b', которая указывает на
соответствие в пределах слова. Например, у нас есть следующая строка: "Языки
обучения: Java, JavaScript, C++". Со временем мы решили, что Java надо заменить на
C#. Но простая замена приведет также к замене строки "JavaScript" на "C#Script", что
недопустимо. И в этом случае мы можем проводить замену, если регуляное
выражение соответствует всему слову:
1 var initialText = "Языки обучения: Java, JavaScript, C++";
2 var exp = /Java\b/g;
3 var result = [Link](exp, "C#");
4 [Link](result); // Языки обучения: C#, JavaScript, C++
142
Но при использовании '\b' надо учитывать, что в JavaScript отсутствует полноценная
поддержка юникода, поэтому применять '\b' мы сможем только к англоязычным
словам.
Использование групп в регулярных выражениях
Для поиска в строке более сложных соответствий применяются группы. В регулярных
выражениях группы заключаются в скобки. Например, у нас есть следующий код html,
который содержит тег изображения: '<img src="[Link]" />'. И допустим, нам надо
вычленить из этого кода пути к изображениям:
1 var initialText = '<img src= "[Link]" />';
2 var exp = /[a-z]+\.(png|jpg)/i;
3 var result = [Link](exp);
4 [Link](function(value, index, array){
5
6 [Link](value + "<br/>");
7 })
Вывод браузера:
[Link]
png
Первая часть до скобок ([a-z]+\.) указывает на наличие в строке от 1 и более символов
из диапазона a-z, после которых идет точка. Так как точка является специальным
символом в регулярных выражениях, то она экранируется слешем. А дальше идет
группа: (png|jpg). Эта группа указывает, что после точки может использоваться как
"png", так и "jpg".
Работа с браузером и BOM
Browser Object Model и объект window
Последнее обновление: 1.11.2015
143
Большое значение в JavaScript имеет работа с веб-браузером и теми объектами,
которые он предоставляет. Например, использование объектов браузера позволяет
манипулировать элементами html, которые имеются на странице, или
взаимодействовать с пользователем.
Все объекты, через которые JavaScript взаимодействует с браузером, описываются
таким понятием как Browser Object Model (Объектная Модель Браузера).
Browser Object Model можно представить в виде следующей схемы:
В вершине находится главный объект - объект window, который представляет собой
браузер. Этот объект в свою очередь включает ряд других объектов, в частности,
объект document, который представляет отдельную веб-страницу, отображаемую в
браузере.
Объект window
Объект window представляет собой окно веб-браузера, в котором размещаются веб-
страницы. window является глобальным объектом, поэтому при доступе к его
свойствам и методам необязательно использовать его имя. Например, window имеет
метод alert(), который отображает окно сообщения. Но нам необязательно писать:
1 [Link]("Привет мир!");
window можно не использовать:
1 alert("Привет мир!");
Но так как данный объект глобальный, то это накладывает некоторые ограничения.
Например:
1 var alert = function(message){
2
3 [Link]("Сообщение: " + message);
4 };
5 [Link]("Привет мир!");
Все объявляемые в программе глобальные переменные или функции автоматически
добавляются к объекту window. И поскольку название новой функции будет совпадать
144
с названием метода alert(), то произойдет переопределение этого метода в объекте
window новой функцией.
И если мы объявим в программе какую-нибудь глобальную переменную, то она нам
доступна как свойство в объекте window:
1 var message = "hello";
2 [Link]([Link]);
Управление окнами
Последнее обновление: 1.11.2015
Диалоговые окна
Для взаимодействия с пользователем в объекте window определен ряд методов,
которые позволяют создавать диалоговые окна.
Метод alert() выводит окно с сообщением:
1 alert("hello world");
Метод confirm() отображает окно с сообщением, в котором пользователь должен
подтвердить действие двух кнопок OK и Отмена. В зависимости от выбора
пользователя метод возвращает true (если пользователь нажал OK) или false (если
пользователь нажал кнопку Отмены):
1 var result = confirm("Завершить выполнение программы?");
2 if(result===true)
3 [Link]("Работа программы завершена");
4 else
5 [Link]("Программа продолжает работать");
145
И метод prompt() позволяет с помощью диалогового окна запрашивать у
пользователя какие-либо данные. Данный метод возвращает введенное
пользователем значение:
1 var age = prompt("Введите свой возраст:");
2 [Link]("Вам " + age + " лет");
Если пользователь откажется вводить значение и нажмет на кнопку отмены, то метод
возвратит значение null.
Открытие, закрытие и позиционирование окон
Объект window также предоставляет ряд методов для управления окнами браузера.
Так, метод open() открывает определенный ресурс в новом окне браузера:
var popup = [Link]('[Link] 'Microsoft', 'width=400, height=4
1 resizable=yes');
Метод open() принимает ряд параметров: путь к ресурсу, описательное название для
окна и в качестве третьего параметра набор стилевых значений окна. Метод
возвращает ссылку на объект нового окна.
Мы можем установить следующие стилевые характеристики:
width: ширина окна в пикселях. Например, width=640
height: высота окна в пикселях. Например, height=480
left: координата X относительно начала экрана в пикселях. Например, left=0
top: координата Y относительно начала экрана в пикселях. Например, top=0
titlebar: будет ли окно иметь строку с заголовком. Например, titlebar=no
menubar: будет ли окно иметь панель меню. Например, menubar=yes
toolbar: будет ли окно иметь панели инструментов. Например, toolbar=yes
location: будет ли окно иметь адресную строку. Например, location=no
scrollbars: допускается ли наличие полос прокрутки.
Например, scrollbars=yes
status: наличие статусной строки. Например, status=yes
146
resizable: может ли окно изменять размеры. Например, resizable=no
С помощью метода close() можно закрыть окно. Например, откроем новое окно и
через 10 секунд закроем его:
var popup = [Link]('[Link] 'Microsoft', 'width=400, height=400,
1
resizable=yes');
2
function closeWindow(){
3 [Link]();
4 }
5 setTimeout(closeWindow, 10000);
Метод moveTo() позволяет переместить окно на новую позицию:
var popup = [Link]('[Link] 'Microsoft', 'width=400, height=400,
1
resizable=yes');
2 [Link](50,50);
В данном случае окно перемещается на позицию с координатами x=50, y=50
относительно левого верхнего угла экрана.
Метод resizeTo() позволяет изменить размеры окна:
var popup = [Link]('[Link] 'Microsoft', 'width=400, height=400,
1
resizable=yes');
2 [Link](500,350); // 500 - ширина и 350 - высота
История браузера. Объект history
Последнее обновление: 1.11.2015
Объект history предназначен для хранения истории посещений веб-страниц в
браузере. Нам этот объект доступен через объект window.
Все сведения о посещении пользователя хранятся в специальном стеке (history stack).
С помощью свойства length можно узнать, как много веб-станиц хранится в стеке:
1 [Link]("В истории " + [Link] + " станиц");
147
Для перемещения по страницам в истории в объекте history определены
методыback() (перемещение к прошлой посмотренной странице)
и forward() (перемещение к следующей просмотренной странице)
1 [Link](); // перемещение назад
Также в объекте history определен специальный метод go(), который позволяет
перемещаться вперед и назад по истории на определенное число страниц. Например,
переместимся на 2 страницы назад:
1 [Link](-2);
Соответственно если надо переместиться на несколько страниц вперед, то в метод
передается положительное значение. Например, переместимся вперед на три
страницы:
1 [Link](3);
Объект location
Последнее обновление: 1.11.2015
Объект location содержит информацию о расположении текущей веб-страницы:
URL, информацию о сервере, номер порта, протокол. С помощью свойств объекта мы
можем получить эту информацию:
href: полная строка запроса к ресурсу
pathname: путь к ресурсу
origin: общая схема запроса
protocol: протокол
port: порт, используемый ресурсом
host: хост
hostname: название хоста
hash: если строка запроса содержит символ решетки (#), то данное свойство
возвращает ту часть строки, которая идет после этого символа
search: если строка запроса содержит знак вопроса (?), например, то данное
свойство возвращает ту часть строки, которая идет после знака вопроса
Например, пусть есть следующая веб-страница [Link], которая лежит на локальном
веб-сервере:
1 <!DOCTYPE html>
148
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <script>
8 [Link]("Строка запроса: " + [Link] + "<br />");
9 [Link]("Путь к ресурсу: " + [Link] + "<br />");
10 [Link]("Схема: " + [Link] + "<br />");
11 [Link]("Протокол: " + [Link] + "<br />");
12 [Link]("Порт: " + [Link] + "<br />");
13 [Link]("Хост: " + [Link] + "<br />");
14 [Link]("Имя хоста: " + [Link] + "<br />");
15 [Link]("Хэш: " + [Link] + "<br />");
16 [Link]("Поиск: " + [Link] + "<br />");
17 </script>
18 </body>
19 </html>
Также объект location предоставляет ряд методов, которые можно использовать для
управления путем запроса:
assign(url): загружает ресурс, который находится по пути url
reload(forcedReload): перезагружает текущую веб-страницу. Параметр
forcedReload указывает, надо ли использовать кэш браузера. Если параметр
равен true, то кэш не используется
replace(url): заменяет текущую веб-станицу другим ресурсом, который
находится по пути url. В отличие от метода assign, который также загружает
веб-станицу с другого ресурса, метод replace не сохраняет предыдущую веб-
страницу в стеке истории переходов history, поэтому мы не сможем вызвать
метод [Link]() для перехода к ней.
Для перенаправления на другой ресурс мы можем использовать как свойства, так и
методы location:
1 location = "[Link]
2 // аналогично
3 // [Link] = "[Link]
4 // [Link]("[Link]
Переход на другой локальный ресурс:
1 [Link]("[Link]");
Объект navigator
149
Последнее обновление: 1.11.2015
Объект navigator содержит информацию о браузере и операционной системе, в
которой браузер запущен. Он определяет ряд свойств и методов, основным из
которых является свойство userAgent, представляющее браузер пользователя:
1 [Link]([Link]);
Данное свойство хранит полную стоку юзер-агента, например, Mozilla/5.0 (Windows
NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157
Safari/537.36
Чтобы вычленить из этой информации непосредственно браузер, можно попробовать
найти в этой информации название браузера:
1
var browser, uAgent = [Link];
2
3 if([Link]("Chrome") > -1) {
4 browser = "Google Chrome";
5 } else if ([Link]("Safari") > -1) {
6 browser = "Apple Safari";
7 } else if ([Link]("Opera") > -1) {
8 browser = "Opera";
9 } else if ([Link]("Firefox") > -1) {
10 browser = "Mozilla Firefox";
} else if ([Link]("MSIE") > -1) {
11
browser = "Microsoft Internet Explorer";
12
}
13
[Link](browser);
14
150
Объект geolocation
Объект navigator хранит свойство geolocation, с помощью которого можно получить
географическое положение пользователя. Для получения положения используется
метод getCurrentPosition(). Этот метод принимает два параметра: функцию, которая
срабатывает при удачном запуске, и функцию, которая срабатывает при ошибке
запроса геоданных:
1
function success(position) {
2
var latitude = [Link];
3 var longitude = [Link];
4 var altitude = [Link];
5 var speed = [Link];
6
7 [Link]("Широта: " + latitude + "<br/>");
8 [Link]("Долгота: " + longitude + "<br/>");
9 [Link]("Высота: " + altitude + "<br/>");
10 [Link]("Скорость перемещения: " + speed + "<br/>");
11 };
12
function error(obj) {
13
[Link]("Ошибка при определении положения");
14
};
15
[Link](success, error);
16
В функцию, которая выполняется при удачном определении геоданных, передается
позиция пользователя в виде параметра position. Передаваемый объект имеет
вложенный объект coords, с помощью свойство которого можно получить
непосредственные координаты пользователя:
latitude: географическая широта
longitude: географическая долгота
altitude: высота
speed: скорость, с которой перемещается пользователь (например, если он
идет или перемещается на транспорте)
151
При этом надо учитывать, что в браузерах действует политика безопасности, которая
при обращении к методу [Link]() отображает
пользователю сообщение, в котором пользователь может подтвердить отправку
географических координат. Если же пользователь откажется, то будет срабатывать
функция error().
Таймеры
Последнее обновление: 1.11.2015
Для выполнения действий через определенные промежутки времени в объекте
window предусмотрены функции таймеров. Есть два типа таймеров: одни
выполняются только один раз, а другие постоянно через промежуток времени.
Функция setTimeout
Для одноразового выполнения действий через промежуток времени предназначена
функция setTimeout(). Она может принимать два параметра:
1 var timerId = setTimeout(someFunction, period)
Параметр period указывает на промежуток, через который будет выполняться
функция из параметра someFunction. А в качестве результата функция возвращает id
таймера.
1 function timerFunction() {
2 [Link]("выполнение функции setTimeout");
3 }
4 setTimeout(timerFunction, 3000);
В данном случае через 3 секунды после загрузки страницы произойдет срабатывание
функции timerFunction.
Для остановки таймера применяется функция clearTimeout().
1 function timerFunction() {
152
2 [Link]("выполнение функции setTimeout");
3 }
4 var timerId = setTimeout(timerFunction, 3000);
5 clearTimeout(timerId);
Функция setInterval
Функции setInterval() и clearInterval() работают аналогично
функциям setTimeout() и clearTimeout() с той лишь разницей,
что setInterval() постоянно выполняет определенную функцию через промежуток
времени.
Например, напишем небольшую программу для вывода текущего времени:
1
<!DOCTYPE html>
2
<html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <div id="time"></div>
8 <script>
9 function updateTime() {
10 [Link]("time").innerHTML = new Date().toTimeString();
}
11
setInterval(updateTime, 1000);
12
</script>
13
</body>
14
</html>
15
Здесь через каждую секунду (1000 миллисекунд) вызывается функция updateTime(),
которая обновляет содержимое поля <div id="time" >, устанавливая в качестве его
кода html текущее вемя.
153
requestAnimationFrame()
Метод requestAnimationFrame() действует аналогично setInterval() за тем
исключением, что он больше заточен под анимации, работу с графикой и имеет ряд
оптимизаций, которые улучшают его производительность.
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
#rect {
6
margin: 100px;
7
width: 100px;
8
height: 100px;
9
background: #50c878;
10
}
11 </style>
12 </head>
13 <body>
14 <div id="rect"></div>
15 <script>
16 var square = [Link]("rect");
17 var angle = 0;
18 function rotate() {
19 angle = (angle + 2)%360;
[Link] = "rotate(" + angle + "deg)";
20
[Link](rotate);
21
}
22
var id = [Link](rotate);
23
</script>
24
</body>
25
</html>
26
154
27
В метод [Link]() передается функция, которая будет
вызываться определенное количество раз (обычно 60) в секунду. В данном случае в
этот метод передается функция rotate, которая изменяет угол поворота блока на
странице и затем обращается опять же к
методу [Link](rotate).
В качестве возвращаемого результата
метод [Link]() возвращает уникальный id, который может
потом использоваться для остановки анимации:
1 [Link](id);
Работа с DOM
Введение в DOM
Последнее обновление: 1.11.2015
Одой из ключевых задач JavaScript является взаимодействие с пользователем и
манипуляция элементами веб-страницы. Для JavaScript веб-страница доступна в виде
объектной модели документа (document object model) или сокращенно DOM. DOM
описывает структуру веб-станицы в виде древовидного представления и
предоставляет разработчикам способ получить доступ к отдельным элементам веб-
станицы.
Важно не путать понятия BOM (Browser Object Model - объектная модель браузера) и
DOM (объектная модель документа). Если BOM предоставляет доступ к браузеру и его
свойствам в целом, то DOM предоставляет доступ к отдельной веб-странице или html-
документу и его элементам.
Например, рассмотрим простейшую страницу:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Page Title</title>
5 </head>
6 <body>
155
7 <h2>Page Header</h2>
8 <div>
9 <h3>Block Header</h3>
10 <p>Text</p>
11 </div>
12 </body>
13 </html>
Дерево DOM для этой страницы будет выглядеть следующим образом:
Таким образом, все компоненты упорядочены в DOM иерархическим образом, где
каждый компонент представляет отдельный узел. То есть каждый элемент,
например, элемент div, представляет собой узел. Но также и текст внутри элемента
представляет отдельный узел.
Существует следующие виды узлов:
Element: html-элемент
Attr: атрибут html-элемента
Document: корневой узел html-документа
DocumentType: DTD или тип схемы XML-документа
DocumentFragment: место для временного хранения частей документа
EntityReference: ссылка на сущность XML-документа
ProcessingInstruction: инструкция обработки веб-страницы
Comment: элемент комментария
Text: текст элемента
CDATASection: секция CDATA в документе XML
Entity: необработанная сущность DTD
Notation: нотация, объявленная в DTD
Несмотря на такое большое количество типов узлов, как правило, мы будем работать
только с некоторыми из них.
Объект document. Поиск элементов
Последнее обновление: 1.11.2015
156
Для работы со структурой DOM в JavaScript предназначен объект document, который
определен в глобальном объекте window. Объект document предоставляет ряд
свойств и методов для управления элементами страницы.
Поиск элементов
Для поиска элементов на странице применяются следующие методы:
getElementById(value): выбирает элемент, у которого атрибут id равен value
getElementsByTagName(value): выбирает все элементы, у которых тег равен
value
getElementsByClassName(value): выбирает все элементы, которые имеют
класс value
querySelector(value): выбирает первый элемент, который соответствует css-
селектору value
querySelectorAll(value): выбирает все элементы, которые соответствуют css-
селектору value
Например, найдем элемент по id:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<div>
7
<h3 id="header">Block Header</h3>
8
<p>Text</p>
9
</div>
10
<script>
11 var headerElement = [Link]("header");
12 [Link]("Текст заголовка: " + [Link]);
13 </script>
14 </body>
157
15
</html>
16
С помощью вызова [Link]("header") находим элемент, у которого
id="header". А с помощью свойства innerText можно получить текст найденного
элемента.
Поиск по определенному тегу:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <div>
<h3>Заголовок</h3>
8
<p>Первый абзац</p>
9
<p>Второй абзац</p>
10
</div>
11
<script>
12
var pElements = [Link]("p");
13
14
for (var i = 0; i < [Link]; i++) {
15
[Link]("Текст параграфа: " + pElements[i].innerText +
16 "<br/>");
17 }
18 </script>
</body>
19
</html>
20
С помощью вызова [Link]("p") находим все элементы
параграфов. Этот вызов возвращает массив найденных элементов. Поэтому, чтобы
получить отдельные элементы массива, необходимо пробежаться по ним в цикле.
158
Если нам надо получить только первый элемент, то можно к первому элементу
найденной коллекции объектов:
1 var pElement = [Link]("p")[0];
2 [Link]("Текст параграфа: " + [Link]);
Получение элемента по классу:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
</head>
6 <body>
7 <div class="article">
8 <h3>Заголовок статьи</h3>
9 <p class="text">Первый абзац</p>
10 <p class="text">Второй абзац</p>
11 </div>
12 <script>
13 var articleDiv = [Link]("article")[0];
[Link](articleDiv);
14
var textElems = [Link]("text");
15
for (var i = 0; i < [Link]; i++) {
16
[Link](textElems[i]);
17
}
18
</script>
19
</body>
20
</html>
21
Выбор по селектору css:
1 <!DOCTYPE html>
159
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
</head>
6 <body>
7 <div class="annotation">
8 <p>Аннотация статьи</p>
9 </div>
10 <div class="text">
11 <p>Первый абзац</p>
12 <p>Второй абзац</p>
13 </div>
<script>
14
var elem = [Link](".annotation p");
15
[Link]("Текст селектора: " + [Link]);
16
</script>
17
</body>
18
</html>
19
Выражение [Link](".annotation p") находит элемент, который
соответствует селектору .annotation p. Если на странице несколько элементов,
соответствующих селектору, то метод выберет первый из них. В итоге браузер
выведет:
Аннотация статьи
Первый абзац
Второй абзац
Текст селектора: Аннотация статьи
160
Чтобы получить все элементы по селектору, можно подобным образом использовать
метод [Link], который возвращает массив найденных
элементов:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <div class="annotation">
8 <p>Аннотация статьи</p>
</div>
9
<div class="text">
10
<p>Первый абзац</p>
11
<p>Второй абзац</p>
12
</div>
13
<script>
14
var elems = [Link](".text p");
15
16
for (var i = 0; i < [Link]; i++) {
17
[Link]("Текст селектора " + i + ": " + elems[i].innerText +
18 "<br/>");
19 }
</script>
20
</body>
21
</html>
22
Вывод браузера:
Аннотация статьи
Первый абзац
161
Второй абзац
Текст селектора 0: Первый абзац
Текст селектора 1: Второй абзац
Свойства объекта document
Последнее обновление: 1.11.2015
Кроме ранее рассмотренных методов объект document позволяет обратиться к
определенным элементам веб-страницы через свойства:
documentElement: предоставляет доступ к корневому элементу <html>
body: предоставляет доступ к элементу <body> на веб-странице
images: содержит коллекцию всех объектов изображений (элементов img)
links: содержит коллекцию ссылок - элементов <a> и <area>, у которых
определен атрибут href
anchors: предоставляет доступ к коллекции элементов <a>, у которых
определен атрибут name
forms: содержит коллекцию всех форм на веб-странице
Эти свойства не предоставляют доступ ко всем элементам, однако позволяют
получить наиболее часто используемые элементы на веб-странице. Например,
получим корневой узел документа:
1 var container = [Link];
Получим все изображения на странице:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <img src="[Link]" alt="Картинка 1" />
8 <img src="[Link]" alt="Картинка 2" />
9 <img src="[Link]" alt="Картинка 3" />
10 <script>
11 var images = [Link];
12 // изменим первое изображение
162
13 images[0].src="pics/picture_4.jpg";
14 images[0].alt="Новая картинка";
15 // перебирем все изображения
16 for(var i=0; i<[Link];i++){
17
18 [Link]("<br/>" + images[i].src);
19 [Link]("<br/>" + images[i].alt);
20 }
21 </script>
22 </body>
23 </html>
Подобно тому, как в коде html мы можем установить атрибуты у элемента img, так и в
коде javascript мы можем через свойства src и alt получить и установить значения
этих атрибутов.
Рассмотрим получение всех ссылок на странице:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <a href="[Link]">Статья 1</a>
8 <a href="[Link]">Статья 2</a>
9 <a href="[Link]">Статья 3</a>
10 <script>
11 var links = [Link];
12
13 for(var i=0; i<[Link];i++){
14
15 [Link]("<br/>" + links[i].innerText);
16 [Link]("<br/>" + links[i].href);
17 }
18 </script>
19 </body>
20 </html>
Опять же, так как у ссылки определен атрибут href, то при переборе ссылок мы
можем получить его значение.
Объект Node. Навигация по DOM
Последнее обновление: 1.11.2015
163
Каждый отдельный узел, будь то html-элемент, его атрибут или текст, в структуре
DOM представлен объектом Node. Этот объект предоставляет ряд свойств, с
помощью которых мы можем получить информацию о данном узле:
childNodes: содержит коллекцию дочерних узлов
firstChild: возвращает первый дочерний узел текущего узла
lastChild: возвращает последний дочерний узел текущего узла
previousSibling: возвращает предыдущий элемент, который находится на
одном уровне с текущим
nextSibling: возвращает следующий элемент, который находится на одном
уровне с текущим
ownerDocument: возвращает корневой узел документа
parentNode: возвращает элемент, который содержит текущий узел
nodeName: возвращает имя узла
nodeType: возвращает тип узла в виде числа
nodeValue: возвращает или устанавливает значение узла в виде простого
текста
Перебирем все дочерние узлы элемента:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<div class="article">
7
<h3>Заголовок статьи</h3>
8
<p>Первый абзац</p>
164
9
10 <p>Второй абзац</p>
11 </div>
12 <script>
13 var articleDiv = [Link]("[Link]");
var nodes = [Link];
14
for(var i=0; i<[Link];i++){
15
16
var type = "";
17
if(nodes[i].nodeType===1)
18
type="элемент";
19
else if(nodes[i].nodeType===2)
20
type="атрибут";
21
else if(nodes[i].nodeType===3)
22 type="текст";
23
24 [Link](nodes[i].nodeName + ": " + type);
25 }
26 </script>
27 </body>
28 </html>
29
С помощью метода [Link]("[Link]") выбираем элемент div с
классом article и пробегаемся по его дочерним узлам. И в цикле выводим имя узла и
его тип с помощью свойств nodeName и nodeType. Каждому типу соответствует
определенное число:
nodeTyp Тип
e узла
1 элемен
т
2 атрибу
т
3 текст
165
Но несмотря на то, что в блоке div на странице только три узла: h3 и 2 параграфа, но
консоль отобразит нам пять узлов.
Дело в том, что пробелы между узлами также считаются за отдельные текстовые
узлы. Если бы пробелов не было:
<div class="article"><h3>Заголовок статьи</h3><p>Первый абзац</p><p>Второй
1 абзац</p></div>
То при переборе мы бы обнаружили только три дочерних узла, как и ожидалось.
Навигация по узлам
Используя свойства nextSibling и previousSibling можно также пройтись по узлам в
прямом или обратном порядке. Например, для прохода по элементам на той же
станице мы могли бы использовать следующий код javascript:
1 var articleDiv = [Link]("[Link]");
2
3 // получаем первый дочерний элемент
4 var node = [Link];
5 [Link]([Link]);
6 // обращаемся к следующему узлу, пока он определен
7 while((node=[Link])!==null){
8
9 [Link]([Link]);
}
10
Тут все аналогично, только в цикле мы обращаемся к следующему узлу, который
находится на одном уровне с текущим (или сестринскому узлу). И результат будет
такой же.
Также можно перебрать узлы в обратном порядке: сначала получаем последний узел,
а затем обращаемся к предыдущему сестринскому узлу:
1 var articleDiv = [Link]("[Link]");
2
166
3 // получаем первый дочерний элемент
4 var node = [Link];
5 [Link]([Link]);
6 // обращаемся к предыдующему узлу, пока он определен
7 while((node=[Link])!==null){
8
9 [Link]([Link]);
}
10
Создание, добавление и удаление
элементов веб-станицы
Последнее обновление: 1.11.2015
Для создания элементов объект document имеет следующие методы:
createElement(elementName): создает элемент html, тег которого передается
в качестве параметра. Возвращает созданный элемент
createTextNode(text): создает и возвращает текстовый узел. В качестве
параметра передается текст узла.
1 var elem = [Link]("div");
2 var elemText = [Link]("Привет мир");
Таким образом, переменная elem будет хранить ссылку на элемент div. Однако
одного создания элементов недостаточно, их еще надо добавить на веб-страницу.
Для добавления элементов мы можем использовать один из методов объекта Node:
appendChild(newNode): добавляет новый узел newNode в конец коллекции
дочерних узлов
167
insertBefore(newNode, referenceNode): добавляет новый узел newNode
перед узлом referenceNode
Используем метод appendChild:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
</head>
6
<body>
7
<div class="article">
8 <h3>Заголовок статьи</h3>
9 <p>Первый абзац</p>
10 <p>Второй абзац</p>
11 </div>
12 <script>
13 var articleDiv = [Link]("[Link]");
14 // создаем элемент
15 var elem = [Link]("h2");
// создаем для него текст
16
var elemText = [Link]("Привет мир");
17
// добавляем текст в элемент в качестве дочернего элемента
18
[Link](elemText);
19
// добавляем элемент в блок div
20
[Link](elem);
21
</script>
22
</body>
23 </html>
24
Сначала создаем обычный элемент заголовка h2 и текстовый узел. Затем текстовый
узел добавляем в элемент заголовка. Затем заголовок добавляем в один из элементов
веб-страницы:
168
Однако нам необязательно для определения текста внутри элемента создавать
дополнительный текстовый узел, так как мы можем воспользоваться
свойством textContent и напрямую ему присвоить текст:
1 var elem = [Link]("h2");
2 [Link] = "Привет мир";
В этом случае текстовый узел будет создан неявно при установке текста.
Теперь рассмотрим, как аналогичный элемент добавить в начало коллекции дочерних
узлов блока div:
1 var articleDiv = [Link]("[Link]");
2 // создаем элемент
3 var elem = [Link]("h2");
4 // создаем для него текст
5 var elemText = [Link]("Привет мир");
6 // добавляем текст в элемент в качестве дочернего элемента
7 [Link](elemText);
8 // получаем первый элемент, перед которым будет идти добавление
var firstElem = [Link];
9
// добавляем элемент в блок div перед первым узлом
10
[Link](elem, firstElem);
11
Если нам надо вставить новый узел на второе, третье или любое другое место, то нам
надо найти узел, перед которым надо вставлять, с помощью комбинаций свойств
firstChild/lastChild и nextSibling/previousSibling.
Копирование элемента
Иногда элементы бывают довольно сложными по составу, и гораздо проще их
скопировать, чем с помощью отдельных вызовов создавать из содержимое. Для
копирования уже имеющихся узлов у объекта Node можно использовать
метод cloneNode():
1 var articleDiv = [Link]("[Link]");
169
2 // клонируем элемент articleDiv
3 var newArticleDiv = [Link](true);
4 // добавляем в конец элемента body
5 [Link](newArticleDiv);
В метод cloneNode() в качестве параметра передается логическое значение: если
передается true, то элемент будет копироваться со всеми дочерними узлами; если
передается false - то копируется без дочерних узлов. То есть в данном случае мы
копируем узел со всем его содержимым и потом добавляем в конец элемента body.
Удаление элемента
Для удаления элемента вызывается метод removeChild() объекта Node. Этот метод
удаляет один из дочерних узлов:
1 var articleDiv = [Link]("[Link]");
2 // находим узел, который будем удалять - первый параграф
3 var removableNode = [Link]("[Link] p")[0];
4 // удаляем узел
5 [Link](removableNode);
В данном случае удаляется первый параграф из блока div
Замена элемента
Для замены элемента применяется метод replaceChild(newNode, oldNode) объекта
Node. Этот метод в качестве первого параметра принимает новый элемент, который
заменяет старый элемент oldNode, передаваемый в качестве второго параметра.
1 var articleDiv = [Link]("[Link]");
2 // находим узел, который будем заменять - первый параграф
3 var oldNode = [Link]("[Link] p")[0];
// создаем элемент
4
var newNode = [Link]("h2");
5
// создаем для него текст
6
var elemText = [Link]("Привет мир");
7
170
8 // добавляем текст в элемент в качестве дочернего элемента
9 [Link](elemText);
10 // заменяем старый узел новым
11 [Link](newNode, oldNode);
В данном случае заменяем первый параграф заголовком h2:
Объект Element. Управление элементами
Последнее обновление: 1.11.2015
Кроме методов и свойств объекта Node в JavaScript мы можем использовать свойства и
методы объектов Element. Важно не путать эти два объекта: Node и Element. Node
представляет все узлы веб-станицы, в то время как объект Element представляет
непосредственно только html-элементы. То есть объекты Element - это фактически те
же самые узлы - объекты Node, у которых тип узла (свойство nodeType) равно 1.
Одним из ключевых свойств объекта Element является свойство tagName, которое
возвращает тег элемента. Например, получим все элементы, которые есть на
странице:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<div class="article">
7
<h3>Заголовок статьи</h3>
8
<p>Первый абзац</p>
9
<p>Второй абзац</p>
10
171
11
</div>
12
<script>
13
function getChildren(elem){
14
15 for(var i in [Link]){
16
17 if([Link][i].nodeType===1){
18
19 [Link]([Link][i].tagName);
20 getChildren([Link][i]);
21 }
22 }
23 }
24 var root = [Link];
[Link]([Link]);
25
getChildren(root);
26
</script>
27
</body>
28
</html>
29
Здесь вначале получаем те корневого элемента <html> и затем с помощью
рекурсивной функции getChildren получаем все вложенные элементы:
Свойства innerText и innerHTML
Для получения или установки текстового содержимого элемента мы можем
использовать свойство innerText, а для получения или установки кода html -
свойство innerHTML:
1 <!DOCTYPE html>
2 <html>
3 <head>
172
4
<meta charset="utf-8" />
5
</head>
6
<body>
7 <div class="article">
8 <h3>Заголовок статьи</h3>
9 <p>Первый абзац</p>
10 <p>Второй абзац</p>
11 </div>
12 <script>
13 var articleDiv = [Link]("[Link]");
14 [Link]([Link]);
[Link]("_______________________");
15
[Link]([Link]);
16
</script>
17
</body>
18
</html>
19
Надо отметить, что свойство innerText во многом аналогично свойству textContent. То
есть следующие вызовы будут равноценны:
1 var pElement = [Link]("[Link] p")[0];
2 [Link] = "hello";
3 [Link] = "hello";
Установка кода html у элемента:
1 var articleDiv = [Link]("[Link]");
2 [Link] ="<h2>Hello World!!!</h2><p>bla bla bla</p>";
Методы объекта Element
Среди методов объекта Element можно отметить методы управления атрибутами:
getAttribute(attr): возвращает значение атрибута attr
173
setAttribute(attr, value): устанавливает для атрибута attr значение value.
Если атрибута нет, то он добавляется
removeAttribute(attr): удаляет атрибут attr и его значение
Работа с атрибутами:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
</head>
6
<body>
7
<div class="article" style="color:red;">
8 <h3>Заголовок статьи</h3>
9 <p>Первый абзац</p>
10 <p>Второй абзац</p>
11 </div>
12 <script>
13 var articleDiv = [Link]("[Link]");
14 // получаем атрибут style
15 var styleValue = [Link]("style");
[Link]("До изменения атрибута: " + styleValue);
16
// удаляем атрибут
17
[Link]("style");
18
// добавляем заново атрибут style
19
[Link]("style", "color:blue;");
20
styleValue = [Link]("style");
21
[Link]("После изменения атрибута: " + styleValue);
22
</script>
23
</body>
24 </html>
25
174
Размеры и позиция элементов
Элементы имеют ряд свойств, которые позволяют определить размер элемента. Но
важно понимать разницу между всеми этими свойствами
Свойства offsetWidth и offsetHeight определяют соответственно ширину и высоту
элемента в пикселях. В ширину и высоту включается граница элемента.
Свойства clientWidth и clientHeight также определяют ширину и высоту элемента в
пикселях, но уже без учета границы:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
#rect {
6
width: 100px;
7
height: 100px;
8
background: #50c878;
9
border: 3px solid silver;
10
}
11 </style>
12 </head>
13 <body>
14 <div id="rect"></div>
15 <script>
16 var rect = [Link]("rect");
17 [Link]("offsetHeight: " + [Link]);
18 [Link]("offsetWidth: " + [Link]);
19 [Link]("clientHeight: " + [Link]);
[Link]("clientWidth: " + [Link]);
20
</script>
21
175
22
</body>
23
</html>
24
Поскольку у блока div определена граница в 3 пикселя, то по сравнению с
clientHeight/clientWidth к offsetHeight/offsetWidth добавляет по 6 пикселей.
Для определения позиции элемента наиболее эффективным способом является
метод getBoundingClientRect().
Этот метод возвращает объект со свойствами top, bottom, left, right, которые
указывают на смещение элемента относительно верхнего левого угла браузера:
1 var rect = [Link]("rect");
2 var clientRect = [Link]();
3 [Link]("top: " + [Link]);
4 [Link]("bottom: " + [Link]);
5 [Link]("left: " + [Link]);
6 [Link]("right: " + [Link]);
Изменение стиля элементов
Последнее обновление: 1.11.2015
Для работы со стилевыми свойствами элементов в JavaScript применяются, главным
образом, два подхода:
Изменение свойства style
Изменение значения атрибута class
176
Свойство style
Свойство style представляет сложный объект для управления стилем и напрямую
сопоставляется с атрибутом style html-элемента. Этот объект содержит набор свойств
CSS: [Link].свойствоCSS. Например, установим цвет шрифта:
1 var root = [Link];
2 // устанавливаем стиль
3 [Link] = "blue";
4 // получаем значение стиля
5 [Link]([Link]); // blue
В данном случае название свойства color совпадает со свойством css. Аналогично мы
могли бы установить цвет с помощью css:
1 html{
2 color:blue;
3 }
Однако ряд свойств css в названиях имеют дефис, например, font-family. В JavaScript
для этих свойств дефис не употребляется. Только первая буква, которая идет после
дефиса, переводится в верхний регистр:
1 var root = [Link];
2 [Link] = "Verdana";
Свойство className
С помощью свойства className можно установить атрибут class элемента html.
Например:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
.blueStyle{
6
color:blue;
7
177
8
font-family:Verdana;
9
}
10
.article{
11
font-size:20px;
12
}
13
</style>
14 </head>
15 <body>
16 <div class="article">
17 <h3>Заголовок статьи</h3>
18 <p>Первый абзац</p>
19 <p>Второй абзац</p>
20 </div>
21 <script>
var articleDiv = [Link]("[Link]");
22
// установка нового класса
23
[Link] = "blueStyle";
24
// получаем название класса
25
[Link]([Link]);
26
</script>
27
</body>
28
</html>
29
Благодаря использованию классов не придется настраивать каждое отдельное
свойство css с помощью свойства style.
Но при этом надо учитывать, что прежнее значение атрибута class удаляется.
Поэтому, если нам надо добавить класс, надо объединить его название со старым
классом:
1 [Link] = [Link] + " blueStyle";
И если надо вовсе удалить все классы, то можно присвоить свойству пустую строку:
178
1 [Link] = "";
Свойство classList
Выше было рассмотрено, как добавлять классы к элементу, однако для управления
множеством классов гораздо удобнее использовать свойство classList. Это свойство
представляет объект, реализующий следующие методы:
add(className): добавляет класс className
remove(className): удаляет класс className
toggle(className): переключает у элемента класс на className. Если класса
нет, то он добавляется, если есть, то удаляется
Например:
1 var articleDiv = [Link]("[Link]");
2 // удаляем класс
3 [Link]("article");
4 // добавляем класс
5 [Link]("blueStyle");
6 // переключаем класс
[Link]("article");
7
События
Введение в обработку событий
Последнее обновление: 1.11.2015
Для взаимодействия с пользователем в JavaScript определен механизм событий.
Например, когда пользователь нажимает кнопку, то возникает событие нажатия
кнопки. В коде JavaScript мы можем определить возникновение события и как-то его
обработать.
179
В JavaScript есть следующие типы событий:
События мыши (перемещение курсора, нажатие мыши и т.д.)
События клавиатуры (нажатие или отпускание клавиши клавиатуры)
События жизненного цикла элементов (например, событие загрузки веб-
станицы)
События элементов форм (нажатие кнопки на форме, выбор элемента в
выпадающем списке и т.д.)
События, возникающие при изменении элементов DOM
События, возникающие при касании на сенсорных экранах
События, возникающие при возникновении ошибок
Рассмотрим простейшую обработку событий. Например, на веб-странице у нас есть
следующий элемент div:
<div id="rect" onclick="alert('Нажато')" style="width:50px;height:50px;background-
1 color:blue;"></div>
Здесь определен обычный блок div, который имеет атрибут onclick, который
задает обработчик события нажатия на блок div. То есть, чтобы обработать какое-
либо событие, нам надо определить для него обработчик. Обработчик представляет
собой код на языке JavaScript. В данном случае обработчик выглядит довольно просто:
1 alert('Нажато')
И при нажатии на кнопку будет выскакивать сообщение:
Также можно было бы вынести все действия по обработке события в отдельную
функцию:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
180
6 <body>
7 <div id="rect" onclick="displayMessage()" style="width:50px;height:50px;background
color:blue;"></div>
8
<script>
9
function displayMessage(){
10
11 alert('Нажато');
12 }
13 </script>
14 </body>
15 </html>
Теперь обработчиком события будет выступать функция displayMessage.
Передача параметров в обработчик события
В обработчик можно передавать параметры. Например, мы можем передать текущий
объект, на котором возникает событие:
1 <a href="[Link]" onclick="return handler(this)">Станица 1</a>
2 <script>
3 function handler(obj){
4
5 alert([Link]);
6 return false;
7 }
</script>
8
Ключевое слово this указывает на текущий объект ссылки, на которую производится
нажатие. И в коде обработчика мы можем получить этот объект и обратиться к его
свойствам, например, к свойству href.
Кроме того, надо отметить, что здесь обработчик возвращает результат. Хотя в
первом примере с блоком div от обработчика не требовалось возвращения результата.
Дело в том, что для некоторых обработчиков можно подтвердить или остановить
обработку события. Например, нажатие на ссылку должно привести к переадресации.
Но возвращая из обработчика false, мы можем остановить стандартный путь
181
обработки события, и переадресации не будет. Если же возвращать значение true, то
событие обрабатывается в стандартном порядке.
Если же мы вовсе уберем возвращении результата, то событие будет обрабатываться,
как будто возвращается значение true:
1 <a href="[Link]" onclick="handler(this)">Станица 1</a>
2 <script>
3 function handler(obj){
4
5 alert([Link]);
6 }
7 </script>
Кроме непосредственно элемента-источника события в обработчик мы можем
передавать объект event. Этот объект не определяется разработчиком, это просто
аргумент функции обработчика, который хранит всю информацию о событии.
Например:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
#rect{
6
width:50px;
7
height:50px;
8
background-color:blue;
9
}
10
</style>
11 </head>
12 <body>
13 <div id="rect" onclick="handler(event)"></div>
14 <script>
15 function handler(e){
182
16
17
alert([Link]); // получаем тип события
18
}
19
</script>
20
</body>
21
</html>
22
В данном случае с помощью свойства type объекта event получаем тип события (в
данном случае тип click).
Обработчики событий
Последнее обновление: 1.11.2015
Встроенные обработчики
В прошлой теме были рассмотрены встроенные обработчики (inline event handler),
которые определяются в коде элемента с помощью атрибутов:
1 <div id="rect" onclick="handler(event)"></div>
Хотя этот подход прекрасно работает, но он имеет кучу недостатков:
Код html смешивается с кодом JavaScript, в связи с чем становится труднее
разрабатывать, отлаживать и поддерживать приложение
Обработчики событий можно задать только для уже созданных на веб-
странице элементов. Динамически создаваемые элементы в этом случае
лишаются возможности обработки событий
К элементу для одного события может быть прикреплен только один
обработчик
Нельзя удалить обработчик без изменения кода
183
Свойства обработчиков событий
Проблемы, которые возникают при использовании встроенных обработчиков, были
призваны решить свойства обработчиков. Подобно тому, как у html-элементов есть
атрибуты для обработчиков, так и в коде javascript у элементов DOM мы можем
получить свойства обработчиков, которые соответствуют атрибутам:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
<style>
6
#rect{
7 width:50px;
8 height:50px;
9 background-color:blue;
10 }
11 </style>
12 </head>
13 <body>
14 <div id="rect"></div>
<script>
15
function handler(e){
16
17
alert([Link]);
18
}
19
[Link]("rect").onclick = handler;
20
</script>
21
</body>
22
</html>
23
184
В итоге нам достаточно взять свойство onclick и присвоить ему функцию,
используемую в качестве обработчика. За счет этого код html отделяется от кода
javascript.
Стоит также отметить, что в обработчик события браузер автоматически передает
объект Event, хранящий всю информацию о событии. Поэтому также мы можем
получить этот объект в функции обработчика в качестве параметра.
Слушатели событий
Несмотря на то, что свойства обработчиков решают ряд проблем, которые связаны с
использованием атрибутов, в то же время это также не оптимальный подход. Еще
один способ установки обработчиков событий представляет использование
слушателей.
Для работы со слушателями событий в JavaScript есть объект EventTarget, который
определяет методы addEventListener() (для добавления слушателя)
и removeEventListener() для удаления слушателя. И поскольку html-элементы DOM
тоже являются объектами EventTarget, то они также имеют эти методы. Фактически
слушатели представляют те же функции обработчиков.
Метод addEventListener() принимает два параметра: название события без префикса
on и функцию обработчика этого события. Например:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
#rect{
6
width:50px;
7
height:50px;
8
background-color:blue;
9
}
10
</style>
11 </head>
12 <body>
13 <div id="rect"></div>
14 <script>
185
15
var rect = [Link]("rect");
16
17
[Link]("click", function (e) {
18
alert([Link]);
19
});
20
</script>
21
</body>
22 </html>
23
То есть в данном случае опять же обрабатывается событие click. И также можно было
бы в качестве второго параметра название функции:
1 function handler(e){
2
3 alert([Link]);
4 }
5 var rect = [Link]("rect");
6
7 [Link]("click", handler);
Удаление слушателя аналогично добавлению:
1 [Link]("click", handler);
Преимуществом использования слушателей является и то, что мы можем установить
для одного события несколько функций:
1 var clicks = 0;
2 function handlerOne(e){
3
4 alert([Link]);
}
5
function handlerTwo(e){
6
186
7
8 clicks++;
9 var newNode = [Link]("p");
10 [Link] = "произошло нажатие " + clicks;
11 [Link](newNode);
12 }
13 var rect = [Link]("rect");
14 // прикрепляем первый обработчик
15 [Link]("click", handlerOne);
// прикрепляем второй обработчик
16
[Link]("click", handlerTwo);
17
Объект Event
Последнее обновление: 1.11.2015
При обработке события браузер автоматически передает в функцию обработчика в
качестве параметра объект Event, который инкапсулирует всю информацию о
событии. И с помощью его свойств мы можем получить эту информацию:
bubbles: возвращает true, если событие является восходящим. Например, если
событие возникло на вложенном элементе, то оно может быть обработано на
родительском элементе.
cancelable: возвращает true, если можно отменить стандартную обработку
события
currentTarget: определяет элемент, к которому прикреплен обработчик
события
defaultPrevented: возвращает true, если был вызван у объекта Event
метод preventDefault()
187
eventPhase: определяет стадию обработки события
target: указывает на элемент, на котором было вызвано событие
timeStamp: хранит время возникновения события
type: указывает на имя события
Например:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
#rect{
6
width:50px;
7
height:50px;
8
background-color:blue;
9
}
10
</style>
11 </head>
12 <body>
13 <div id="rect"></div>
14 <script>
15 function handler(event){
16
17 [Link]("Тип события: " + [Link]);
18
19 [Link]([Link]);
20 }
21 var rect = [Link]("rect");
[Link]("click", handler);
22
</script>
23
</body>
188
24
25 </html>
26
Причем в данном случае свойство target представляет собой элемент, поэтому мы
можем манипулировать им как и любыми другими узлами и элементами DOM.
Например, изменим фоновый цвет:
1 function handler(e){
2
3 [Link] = "red";
4 }
Остановка выполнения события
С помощью метода preventDefault() объекта Event мы можем остановить
дальнейшее выполнение события. В ряде случаев этот метод не играет большой роли.
Однако в некоторых ситуаций он может быть полезен. Например, при нажатии на
ссылку мы можем с помощью дополнительной обработки определить, надо ли
переходить по ссылке или надо запретить переход. Или другой пример: пользователь
отправляет данные формы, но в ходе обработки в обработчике события мы
определили, что поля формы заполнены неправильно, и в этом случае мы также
можем запретить отправку.
Например, запретим переход по ссылке после 12 часов:
1 <a href="[Link] id="link">Поиск</a>
2 <script>
3 function linkHandler(e){
4
var date = new Date();
5
var hour = [Link]();
6
[Link](hour);
7
if(hour>12){
8
9
[Link]();
10
[Link]("После 12 переход запрещен");
11
189
12 }
13 }
14 var link = [Link]("link");
15 [Link]("click", linkHandler);
16 </script>
Распространение событий
Последнее обновление: 1.11.2015
Когда мы нажимаем на какой-либо элемент на станице и генерируется событие
нажатия, то это событие может распространяться от элемента к элементу. Например,
если мы нажимаем на блок div, то также мы нажимаем и на элемент body, в котором
блок div находится. То есть происходит распространение события.
Есть несколько форм распространения событий:
Восходящие: событие распространяется вверх по дереву DOM от дочерних
узлов к родительским
Нисходящие: событие распространяется вниз по дереву DOM от родительских
узлов к дочерним, пока не достигнет того элемента, на котором это событие и
возникло
Восходящие события
Рассмотрим восходящие (bubbling) события, которые распространяются в верх по
дереву DOM. Допустим, у нас есть следующая веб-страница:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
<style>
5
190
6 #blueRect{
7 width:100px;
8 height:100px;
background-color:blue;
9
}
10
#redRect{
11
width:50px;
12
height:50px;
13
background-color:red;
14
}
15
</style>
16 </head>
17 <body>
18 <div id="blueRect">
19 <div id="redRect"></div>
20 </div>
21
22 <script>
23 var redRect = [Link]("redRect");
24 [Link]("click", function(){
25 [Link]("Событие на redRect");
});
26
27
var blueRect = [Link]("blueRect");
28
[Link]("click", function(){
29
[Link]("Событие на blueRect");
30
});
31
32
[Link]("click", function(){
33
[Link]("Событие на body");
34
});
191
35
36 </script>
37 </body>
38 </html>
39
Если мы нажмем на вложенный div, то событие пойдет к родительскому элементу div
и далее к элементу body:
Надо сказать, что подобное поведение не всегда является желательным. И в этом
случае мы можем остановить распространение событие с помощью
метода stopPropagation() объекта Event:
1 var redRect = [Link]("redRect");
2 [Link]("click", function(e){
3 [Link]("Событие на redRect");
4 [Link]();
5 });
И в результате нажатия событие будет обработано только обработчиком для redRect.
Нисходящие события
События также могут быть нисходящими (capturing). Для их использования в
метод addEventListener() в качестве третьего необязательного параметра
передается логическое значение true или false, которое указывает, будет ли событие
нисходящим. По умолчанию все события восходящие.
Возьмем ту же веб-станицу, только изменим ее код javascript:
1 var redRect = [Link]("redRect");
2 [Link]("click", function(){
3 [Link]("Событие на redRect");
}, true);
4
5
var blueRect = [Link]("blueRect");
192
6
[Link]("click", function(){
7
[Link]("Событие на blueRect");
8
}, true);
9
10
[Link]("click", function(){
11
[Link]("Событие на body");
12
}, true);
13
Теперь события будут распространяться в обратном порядке:
События мыши
Последнее обновление: 1.11.2015
Одну из наиболее часто используемых событий составляют события мыши:
click: возникает при нажатии указателем мыши на элемент
mousedown: возникает при нахождении указателя мыши на элементе, когда
кнопка мыши находится в нажатом состоянии
mouseup: возникает при нахождении указателя мыши на элементе во время
отпускания кнопки мыши
mouseover: возникает при вхождении указателя мыши в границы элемента
mousemove: возникает при прохождении указателя мыши над элементом
mouseout: возникает, когда указатель мыши выходит за пределы элемента
Например, обработаем события mouseover и mouseout:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <style>
6 #blueRect{
7 width:100px;
8 height:100px;
9 background-color:blue;
193
10 }
11 </style>
12 </head>
13 <body>
14 <div id="blueRect"></div>
15
16 <script>
17 function setColor(e){
18
19 if([Link]==="mouseover")
20 [Link] = "red";
21 else if([Link]==="mouseout")
22 [Link] = "blue";
23 }
24 var blueRect = [Link]("blueRect");
25 [Link]("mouseover", setColor);
26 [Link]("mouseout", setColor);
27 </script>
28 </body>
29 </html>
Теперь при наведении указателя мыши на блок blueRect он будет окрашиваться в
красный цвет, а при уходе указателя мыши - блок будет обратно окрашиваться в
синий цвет.
Объект Event является общим для всех событий. Однако для разных типов событий
существуют также свои объекты событий, которые добавляют ряд своих свойств. Так,
для работы с событиями указателя мыши определен объект MouseEvent, который
добавляет следующие свойства:
altKey: возвращает true, если была нажата клавиша Alt во время генерации
события
button: указывает, какая кнопка мыши была нажата
clientX: определяет координату Х окна браузера, на которой находился
указатель мыши во время генерации события
clientY: определяет координату Y окна браузера, на которой находился
указатель мыши во время генерации события
ctrlKey: возвращает true, если была нажата клавиша Ctrl во время генерации
события
metaKey: возвращает true, если была нажата во время генерации события
метаклавиша клавиатуры
relatedTarget: определяет вторичный источник возникновения события
screenX: определяет координату Х относительно верхнего левого угла экрана
монитора, на которой находился указатель мыши во время генерации события
screenY: определяет координату Y относительно верхнего левого угла экрана
монитора, на которой находился указатель мыши во время генерации события
194
shiftKey: возвращает true, если была нажата клавиша Shift во время
генерации события
Определим координаты клика:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <style>
6 #blueRect{
7 width:100px;
8 height:100px;
9 background-color:blue;
10 }
11 </style>
12 </head>
13 <body>
14 <div id="blueRect"></div>
15
16 <script>
17 function handleClick(e){
18
19 [Link]("screenX: " + [Link]);
20 [Link]("screenY: " + [Link]);
21 [Link]("clientX: " + [Link]);
22 [Link]("clientY: " + [Link]);
23 }
24 var blueRect = [Link]("blueRect");
25 [Link]("click", handleClick);
26 </script>
27 </body>
28 </html>
События клавиатуры
Последнее обновление: 1.11.2015
Другим распространенным типом событий являются события клавиатуры.
keydown: возникает при нажатии клавиши клавиатуры и длится, пока нажата
клавиша
keyup: возникает при отпускании клавиши клавиатуры
195
keypress: возникает при нажатии клавиши клавиатуры, но после события
keydown и до события keyup. Надо учитывать, что данное событие
генерируется только для тех клавиш, которые формируют вывод в виде
символов, например, при печати символов. Нажатия на остальные клавиши,
например, на Alt, не учитываются.
Для работы с событиями клавиатуры определен объект KeyboardEvent, который
добавляет к свойствам объекта Event ряд специфичных для клавиатуры свойств:
altKey: возвращает true, если была нажата клавиша Alt во время генерации
события
charCode: возвращает символ Unicode для нажатой клавиши (используется для
события keypress)
keyCode: возвращает числовое представление нажатой клавиши клавиатуры
ctrlKey: возвращает true, если была нажата клавиша Ctrl во время генерации
события
metaKey: возвращает true, если была нажата во время генерации события
метаклавиша клавиатуры
shiftKey: возвращает true, если была нажата клавиша Shift во время
генерации события
Например, мы можем с помощью клавиш клавиатуры перемещать элемент на веб-
странице:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <style>
6 html, body{
7 margin:0;
8 overflow:hidden;
9 }
10 #blueRect{
11 width:100px;
12 height:100px;
13 background-color:blue;
14 }
15 </style>
16 </head>
17 <body>
18 <div id="blueRect"></div>
19
20 <script>
21 function moveRect(e){
22
23 var blueRect = [Link]("blueRect");
196
24 // получаем стиль для blueRect
25 var cs = [Link](blueRect);
26
27 var left = parseInt([Link]);
28 var top = parseInt([Link]);
29
30 switch([Link]){
31
32 case 37: // если нажата клавиша влево
33 if(left>0)
34 [Link] = left - 10 + "px";
35 break;
36 case 38: // если нажата клавиша вверх
37 if(top>0)
38 [Link] = top - 10 + "px";
39 break;
40 case 39: // если нажата клавиша вправо
41 if(left < [Link] - 100)
42 [Link] = left + 10 + "px";
43 break;
44 case 40: // если нажата клавиша вниз
45 if(top < [Link] - 100)
46 [Link] = top + 10 + "px";
47 break;
48 }
49 }
50
51 addEventListener("keydown", moveRect);
52 </script>
53 </body>
54 </html>
В данном случае обрабатывается событие keydown. В обработчике moveRect с
помощью метода [Link]() получаем стиль элемента blueRect. А
затем из этого стиля выбираем значения свойств marginLeft и marginTop.
С помощью свойства [Link] получаем нажатую клавишу. Список кодов клавиш
клавиатуры можно посмотреть на сайте [Link]
Здесь нам интересуют четыре клавиши: вверх, вниз, влево, вправо. Если одна из них
нажата, производим действия: увеличение или уменьшение отступа элемента от
верхней или левой границы. Ну и чтобы элемент не выходил за границы окна,
проверяем предельные значения с помощью [Link]
(ширина корневого элемента) и [Link] (высота
корневого элемента).
Работа с формами
197
Формы и их элементы
Последнее обновление: 1.11.2015
Один из способов взаимодействия с пользователями представляют html-формы.
Например, если нам надо получить от пользователя некоторую информацию, мы
можем определить на веб-странице формы, которая будет содержать текстовые поля
для ввода информации и кнопку для отправки. И после ввода данных мы можем
обработать введенную информацию.
Для создания формы используется элемент <form>:
1 <form name="search">
2 </form>
В JavaScript форма представлена объектом HtmlFormElement. И после создания
формы мы можем к ней обратиться различными способами.
Первый способ заключается в прямом обращении по имени формы:
1 var searchForm = [Link];
Второй способ состоит в обращении к коллекции форм документа и поиске в ней
нужной формы:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<form name="search"></form>
7
<form name="settings"></form>
8
198
9 <script>
10 var searchForm;
11 for (var i = 0; i < [Link]; i++) {
12
13 if([Link][i].name==="search")
14 searchForm = [Link][i];
15 }
16 [Link]([Link]);
17 </script>
</body>
18
</html>
19
С помощью свойства name объекта формы мы можем получить значение
атрибута name у соответствующего элемента формы в коде html.
Еще один способ сочетает оба подхода:
1 var searchForm = [Link]["search"];
И также можно применять стандартные способы для поиска элемента формы,
например, по id, по тегу или по селектору. Например:
1 var searchForm = [Link]("form")[0]
Форма имеет ряд свойств, из которых наиболее важными являются
вышерассмотренное свойство name, а также свойство elements, которое содержит
коллекцию элементов формы:
1 <form name="search">
2 <input type="text" name="key"></input>
3 <input type="submit" name="send"></input>
</form>
4
<script>
5
var searchForm = [Link]["search"];
6
for(var i=0; i<[Link];i++)
7
[Link]([Link][i].name + "<br/>");
199
8
</script>
9
Среди методов формы надо отметить метод submit(), который отправляет данные
формы на сервер, и метод reset(), который очищает поля формы:
1 var searchForm = [Link]["search"];
2 [Link]();
3 [Link]();
Элементы форм
Форма может содержать различные элементы ввода html: input, textarea, button, select
и т.д. Но все они имеют ряд общих свойств и методов.
Также, как и форма, элементы форм имеют свойство name, с помощью которого
можно получить значение атрибута name:
1
<form name="search">
2 <input type="text" name="key" value="hello world"></input>
3 <input type="submit" name="send"></input>
4 </form>
5 <script>
6 var searchForm = [Link]["search"];
7 // выведем имя всех элементов
8 for(var i=0; i<[Link];i++)
9 [Link]([Link][i].name + "<br/>");
10
// получим по имени текстовое поле
11
var keyBox = [Link]["key"];
12
[Link]([Link]); // key
13
</script>
14
Другим важным свойством является свойство value, которое позволяет получить или
изменить значение поля:
200
1 var searchForm = [Link]["search"];
2 var keyBox = [Link]["key"];
3 [Link]([Link]); // hello world
4 // установка значения
5 [Link] = "Привет мир";
С помощью свойства form можно получить родительский объект формы:
1 var searchForm = [Link]["search"];
2 var keyBox = [Link]["key"];
3 [Link]([Link]); // search
Данное свойство может быть полезно, например, при отправке формы, когда перед
непосредственной отправкой формы необходимо провести валидацию всех полей
формы.
Свойство type позволяет получить тип поля ввода. Это либо название тега элемента
(например, textarea), либо значение атрибута type у элементов input.
Из методов можно выделить методы focus() (устанавливает фокус на элемент)
и blur() (убирает фокус с элемента):
1 var searchForm = [Link]["search"];
2 var keyBox = [Link]["key"];
3 [Link]();
Кнопки
Последнее обновление: 1.11.2015
Для отправки введенных данных на форме используются кнопки. Для создания
кнопки используется либо элемент button:
1 <button name="send">Отправить</button>
201
Либо элемент input:
1 <input type="submit" name="send" value="Отправить" />
С точки зрения функциональности в html эти элементы не совсем равноценны, но в
данном случае они нас интересуют с точки зрения взаимодействия с кодом javascript.
При нажатии на любой из этих двух вариантов кнопки происходит отправка формы по
адресу, который указан у формы в атрибуте action, либо по адресу веб-страницы,
если атрибут action не указан. Однако в коде javascript мы можем перехватить
отправку, обрабатывая событие click
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <form name="search">
8 <input type="text" name="key"></input>
9 <input type="submit" name="send" value="Отправить" />
10 </form>
11 <script>
12 function sendForm(e){
13
14 // получаем значение поля key
15 var keyBox = [Link];
16 var val = [Link];
17 if([Link]>5){
18 alert("Недопустимая длина строки");
19 [Link]();
20 }
21 else
22 alert("Отправка разрешена");
23 }
24
25 var sendButton = [Link];
26 [Link]("click", sendForm);
27 </script>
28 </body>
29 </html>
При нажатии на кнопку происходит событие click, и для его обработки к кнопке
прикрепляем обработчик sendForm. В этом обработчике проверяем введенный в
текстовое поле текст. Если его длина больше 5 символов, то выводим сообщение о
недостимой длине и прерываем обычный ход события с помощью
вызова [Link](). В итоге форма не отправляется.
202
Если же длина текста меньше шести символов, то также выводится сообщение, и
затем форма отправляется.
Также мы можем при необходимости при отправке изменить адрес, на который
отправляются данные:
1 function sendForm(e){
2
3 // получаем значение поля key
4 var keyBox = [Link];
5 var val = [Link];
6 if([Link]>5){
7 alert("Недопустимая длина строки");
8 [Link]="PostForm";
9 }
10 else
11 alert("Отправка разрешена");
12 }
В данном случае, если длина текста больше пяти символов, то текст отправляется,
только теперь он отправляется по адресу PostForm, поскольку задано свойство action:
1 [Link]="PostForm";
Для очистки формы предназначены следующие равноценные по функциональности
кнопки:
1 <button type="reset">Очистить</button>
2 <input type="reset" value="Очистить" />
При нажатию на кнопки произойдет очистка форм. Но также функциональность по
очистке полей формы можно реализовать с помощью метода reset():
1 function sendForm(e){
2
3 // получаем значение поля key
4 var keyBox = [Link];
5 var val = [Link];
6 if([Link]>5){
7 alert("Недопустимая длина строки");
8 [Link]();
9 [Link]();
10 }
11 else
12 alert("Отправка разрешена");
13 }
203
Кроме специальных кнопок отправки и очистки на форме также может
использоваться обычная кнопка:
1 <input type="button" name="send" value="Отправить" />
При нажатии на подобную кнопку отправки данных не происходит, хотя также
генерируется событие click:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7 <form name="search">
8 <input type="text" name="key" placeholder="Введите ключ"></input>
9 <input type="button" name="print" value="Печать" />
10 </form>
11 <div id="printBlock"></div>
12 <script>
13 function printForm(e){
14
15 // получаем значение поля key
16 var keyBox = [Link];
17 var val = [Link];
18 // получаем элемент printBlock
19 var printBlock = [Link]("printBlock");
20 // создаем новый параграф
21 var pElement = [Link]("p");
22 // устанавливаем у него текст
23 [Link] = val;
24 // добавляем параграф в printBlock
25 [Link](pElement);
26 }
27
28 var printButton = [Link];
29 [Link]("click", printForm);
30 </script>
31 </body>
32 </html>
При нажатии на кнопку получаем введенный в текстовое поле текст, создаем новый
элемент параграфа для этого текста и добавляем параграф в элемент printBlock.
Текстовые поля
Последнее обновление: 1.11.2015
204
Для ввода простейшей текстовой информации предназначены элементы <input
type="text":
1 <input type="text" name="kye" size="10" maxlength="15" value="hello world" />
Данный элемент поддерживает ряд событий, в частности:
focus: происходит при получении фокуса
blur: происходит при потере фокуса
change: происходит при изменении значения поля
select: происходит при выделении текста в текстовом поле
keydown: происходит при нажатии клавиши клавиатуры
keypress: происходит при нажатии клавиши клавиатуры для печатаемых
символов
keyup: происходит при отпускании ранее нажатой клавиши клавиатуры
Применим ряд событий:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<form name="search">
7
<input type="text" name="key" placeholder="Введите ключ"></input>
8
<input type="button" name="print" value="Печать" />
9
</form>
205
10 <div id="printBlock"></div>
11 <script>
12 var keyBox = [Link];
13
// обработчик изменения текста
14
function onchange(e){
15
// получаем элемент printBlock
16
var printBlock = [Link]("printBlock");
17
// получаем новое значение
18
var val = [Link];
19
// установка значения
20
[Link] = val;
21 }
22 // обработка потери фокуса
23 function onblur(e){
24
25 // получаем его значение и обрезаем все пробелы
26 var text = [Link]();
27 if(text==="")
28 [Link] = "red";
29 else
30 [Link] = "green";
}
31
// получение фокуса
32
function onfocus(e){
33
34
// установка цвета границ поля
35
[Link] = "blue";
36
}
37
[Link]("change", onchange);
38
[Link]("blur", onblur);
206
39
40
[Link]("focus", onfocus);
41
</script>
42
</body>
43
</html>
44
45
Здесь к текстовому полю прикрепляется три обработчика для событий blur, focus и
change. Обработка события change позволяет сформировать что-то вроде привязки:
при изменении текста весь текст отображается в блоке printBlock. Но надо учитывать,
что событие change возникает не сразу после изменения текста, а после потери им
фокуса.
Обработка события потери фокуса blur позволяет провести валидацию введенного
значения. Например, в данном случае если текст состоит из пробелов или не был
введен, то окрашиваем границу поля в красный цвет.
Кроме данного текстового поля есть еще специальные поля ввода. Так, поле <input
type="password" предназначено для ввода пароля. По функциональности оно во
многом аналогично обычному текстовому полю за тем исключением, что для
вводимых символов используется маска:
1 <input type="password" name="password" />
Если нам надо, чтобы на форме было некоторое значение, но чтобы оно было скрыто
от пользователя, то для этого могут использоваться скрытые поля:
1 <input type="hidden" name="id" value="345" />
Для скрытого поля обычно не используется обработка событий, но также, как и для
других элементов, мы можем в javascript получить его значение или изменить его.
Элемент textarea
Для создания многострочных текстовых полей используется элемент textarea:
1 <textarea rows="15" cols="40" name="textArea"></textarea>
207
Данные элемент генерирует все те же самые события, что и обычное текстовое поле:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<form name="search">
7
<textarea rows="7" cols="40" name="message"></textarea>
8
</form>
9
<div id="printBlock"></div>
10
<script>
11 var messageBox = [Link];
12
13 // обработчик ввода символа
14 function onkeypress(e){
15 // получаем элемент printBlock
16 var printBlock = [Link]("printBlock");
17 // получаем введенный символ
18 var val = [Link]([Link]);
19 // добавление символа
20 [Link] += val;
}
21
22
function onkeydown(e){
23
if([Link]===8){ // если нажат Backspace
24
25
// получаем элемент printBlock
26
var printBlock = [Link]("printBlock"),
27
length = [Link];
28
// обрезаем строку по последнему символу
208
29
30 [Link] = [Link](0,
length-1);
31
}
32
}
33
34
[Link]("keypress", onkeypress);
35 [Link]("keydown", onkeydown);
36 </script>
37 </body>
38 </html>
39
Здесь к текстовому полю прикрепляются обработчики для событий keypress и
keydown. В обработчике keypress получаем введенный символ с помощью конвертации
числового кода клавиши в строку:
1 var val = [Link]([Link]);
Затем символ добавляется к содержимому блока printBlock.
Событие keypress возникает при нажатии на клавиши для печатаемых символов, то
такие символы отображаются в текстовом поле. Однако есть и другие клавиши,
которые оказывают влияние на текстовое поле, но они не дают отображаемого
символа, поэтому не отслеживаются событием keypress. К таким клавишам относится
клавиша Backspace, которая удаляет последний символ. И для ее отслеживания
также обрабатываем событие keydown. В обработчике keydown удаляем из строки в
блоке printBlock последний символ.
Флажки и переключатели
Последнее обновление: 1.11.2015
Особую группу элементов ввода составляют флажки и переключатели.
209
Флажки представляют поле, в которое можно поставить отметки и которое создается
с помощью элемента <input type="checkbox". Отличительную особенность флажка
составляет свойство checked, которое в отмеченном состоянии принимает значение
true:
1 <form name="myForm">
2 <input type="checkbox" name="enabled" checked><span>Включить</span>
3 </form>
4 <div id="printBlock"></div>
5 <script>
6 var enabledBox = [Link];
7
8 function onclick(e){
9 var printBlock = [Link]("printBlock");
10 var enabled = [Link];
11 [Link] = enabled;
12 }
13
14 [Link]("click", onclick);
15 </script>
Нажатие на флажок генерирует событие click. В данном случае при обработке
данного события мы просто выводим информацию, отмечен ли данный флажок, в блок
div.
Переключатели представляют группы кнопок, из которых мы можем выбрать только
одну. Переключатели создаются элементом <input type="radio".
Выбор или нажатие на одну из них также представляет событие click:
1 <form name="myForm">
2 <input type="radio" name="languages" checked="checked" value="Java"
3 /><span>Java</span>
4 <input type="radio" name="languages" value="C#" /><span>C#</span>
5 <input type="radio" name="languages" value="C++" /><span>C++</span>
6 </form>
7 <div id="printBlock"></div>
8 <script>
9 function onclick(e){
10
11 var printBlock = [Link]("printBlock");
12 var language = [Link];
13 [Link] = "Вы выбрали: " + language;
14 }
15 for (var i = 0; i < [Link]; i++) {
210
[Link][i].addEventListener("click", onclick);
16
}
17
</script>
При создании группы переключателей их атрибут name должен иметь одно и то же
значение. В данном случае это - languages. То есть переключатели образуют группу
languages.
Поскольку переключателей может быть много, то при прикреплении к ним
обработчика события нам надо пробежаться по всему массиву переключателей,
который можно получить по имени группы:
1 for (var i = 0; i < [Link]; i++) {
2 [Link][i].addEventListener("click", onclick);
3 }
Значение выбранного переключателя также можно получить через объект
Event: [Link]
Каждый переключатель также, как и флажок, имеет свойство checked, которое
возвращает значение true, если переключатель выбран. Например, отметим
последний переключатель:
1 [Link][[Link]-1].checked = true;
Список select
Последнее обновление: 1.11.2015
Для создания списка используется html-элемент select. Причем с его помощью можно
создавать как выпадающие списки, так и обычные с ординарным или множественным
выбором. Например, стандартный список:
1 <select name="language" size="4">
2 <option value="JS" selected="selected">JavaScript</option>
<option value="Java">Java</option>
211
3
<option value="C#">C#</option>
4
<option value="C++">C++</option>
5
</select>
6
Атрибут size позволяет установить, сколько элементов будут отображаться
одномоментно в списке. Значение size="1" отображает только один элемент списка,
а сам список становится выпадающим. Если установить у элемента select
атрибут multiple, то в списке можно выбрать сразу несколько значений.
Каждый элемент списка представлен html-элементом option, у которого есть
отображаемая метка и есть значения в виде атрибута value.
В JavaScript элементу select соответствует объект HTMLSelectElement, а элементу
option - объект HtmlOptionElement или просто Option.
Все элементы списка в javascript доступны через коллекцию options. А каждый
объект HtmlOptionElement имеет свойства: index (индекс в коллекции
options), text (отображаемый текст) и value (значение элемента). Например, получим
первый элемент списка и выведем о нем через его свойства всю информацию:
1
<form name="myForm">
2
<select name="language" size="4">
3 <option value="JS" selected="selected">JavaScript</option>
4 <option value="Java">Java</option>
5 <option value="CS">C#</option>
6 <option value="CPP">C++</option>
7 </select>
8 </form>
9 <script>
10 var firstLanguage = [Link][0];
[Link]("Index: " + [Link] + "<br/>");
11
[Link]("Text: " + [Link] + "<br/>");
12
[Link]("Value: " + [Link] + "<br/>");
13
</script>
14
212
В javascript мы можем не только получать элементы, но и динамически управлять
списком. Например, применим добавление и удаление объектов списка:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<form name="myForm">
7
<select name="language" size="5">
8
<option value="JS" selected="selected">JavaScript</option>
9
<option value="Java">Java</option>
10
<option value="CS">C#</option>
11 <option value="CPP">C++</option>
12 </select>
13 <p><input type="text" name="textInput" placeholder="Введите текст" /></p>
14 <p><input type="text" name="valueInput" placeholder="Введите значение" /></p>
15 <p><input type="button" name="addButton" value="Добавить" /><input type="button
value="Удалить" /></p>
16
</form>
17
18
<script>
19
var addButton = [Link],
20
removeButton = [Link],
21
languagesSelect = [Link];
22
// обработчик добавления элемента
23 function addOption(){
24 // получаем текст для элемента
25 var text = [Link];
26 // получаем значение для элемента
27 var value = [Link];
213
28
29 // создаем новый элемента
30 var newOption = new Option(text, value);
[Link][[Link]]=newOption;
31
}
32
// обработчик удаления элемент
33
function removeOption(){
34
35
var selectedIndex = [Link];
36
// удаляем элемент
37
[Link][selectedIndex] = null;
38
}
39
40 [Link]("click", addOption);
41 [Link]("click", removeOption);
42 </script>
43 </body>
44 </html>
45
Для добавления на форме предназначены два текстовых поля (для текстовой метки и
значения элемента option) и кнопка. Для удаления выделенного элемента
предназначена еще одна кнопка.
За добавление в коде javascript отвечает функция addOption, в которой получаем
введенные в текстовые поля значения, создаем новый объект Option и добавляем его
в массив options объекта списка.
За удаление отвечает функция removeOption, в которой просто получаем индекс
выделенного элемента с помощью свойства selectedIndex и в коллекции options
приравниваем по этому индексу значение null.
Для добавления/удаления также в качестве альтернативы можно использовать
методы элемента select:
214
1 // вместо вызова
2 // [Link][[Link]]=newOption;
3 // использовать для добавления вызов метода add
4 [Link](newOption);
5 // вместо вызова
6 // [Link][selectedIndex] = null;
7 // использовать для удаления метод remove
[Link](selectedIndex);
8
События элемента select
Элемент select поддерживает три события: blur (потеря фокуса), focus (получение
фокуса) и change (изменение выделенного элемента в списке). Рассмотрим
применение события select:
1 <form name="myForm">
2 <select name="language" size="5">
3 <option value="JS" selected="selected">JavaScript</option>
<option value="Java">Java</option>
4
<option value="CS">C#</option>
5
<option value="CPP">C++</option>
6
</select>
7
</form>
8
<div id="selection"></div>
9
<script>
10
var languagesSelect = [Link];
11
12 function changeOption(){
13
14 var selection = [Link]("selection");
15 var selectedOption =
[Link][[Link]];
16
[Link] = "Вы выбрали: " + [Link];
17
}
215
18
19
[Link]("change", changeOption);
20
</script>
21
JSON
Введение в JSON
Последнее обновление: 1.11.2015
JSON (JavaScript Object Notation) представляет легковесный формат хранения данных.
JSON описывает структуру и организацию данных JavaScript. Простота JSON привела к
тому, что в настоящий момент он является наиболее популярным форматом передачи
данных в среде web, вытеснив другой некогда популярный формат xml.
Объекты JSON очень похожи на объекты JavaScript, тем более что JSON является
подмножеством JavaScript. В то же время важно их различать: JavaScript является
языком программирования, а JSON является форматом данных.
JSON поддерживает три типа данных: примитивные значения, объекты и массивы.
Примитивные значения представляют стандартные строки, числа, значение null,
логические значения true и false.
Объекты представляют набор простейших данных, других объектов и массивов.
Например, типичный объект JSON:
1 {
2 "name": "Tom",
3 "married": true,
4 "age": 30
5 }
В javascript этому объекту соответствовал бы следующий:
216
1 var user = {
2 name: "Tom",
3 married: true,
4 age: 30
5 }
Несмотря на общее сходство, в то же время есть и различия: в JSON названия свойств
заключаются в кавычки, как обычные строки. Кроме того, объекты JSON не могут
хранить функции, переменные, как объекты javascript.
Объекты могут быть сложными:
1 {
2 "name": "Tom",
3 "married": true,
4 "age": 30,
5 "company": {
6 "name": "Microsoft",
7 "address": "USA, Redmond"
}
8
}
9
Массивы в JSON похожи на массивы javascript и также могут хранить простейшие
данные или объекты:
1 ["Tom", true, 30]
Массив объектов:
1 [{
2 "name": "Tom",
3 "married": true,
"age": 30
4
},{
5
"name": "Alice",
6
217
7 "married": false,
8 "age": 23
9 }]
Сериализация в JSON и десериализация
Для сериализации объекта javascript в json применяется функция [Link]():
1 var user = {
2 name: "Tom",
3 married: true,
4 age: 30
5 };
6 var serializedUser = [Link](user);
[Link](serializedUser); // {"name":"Tom","married":true,"age":30}
7
Для обратной операции - десериализации или парсинга json-объекта в javascript
применяется метод [Link]():
1 var user = {
2 name: "Tom",
3 married: true,
4 age: 30
5 };
6 // сериализация
7 var serializedUser = [Link](user);
8 // десериализация
var tomUser = [Link](serializedUser);
9
[Link]([Link]); // Tom
10
Хранение данных
Куки
Последнее обновление: 1.11.2015
218
Одну из возможностей сохранения данных в javascript представляет использование
куки. Для работы с куками в объекте document предназначено свойство cookie.
Для установки куков достаточно свойству [Link] присвоить строку с
куками:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 </head>
6 <body>
7
8 <script>
9 [Link] = "login=tom32;";
</script>
10
</body>
11
</html>
12
В данном случае устанавливается кука, которая называется "login" и которая имеет
значение "tom32". И в большинстве браузеров мы можем посмотреть ее, узнать всю
информацию о ней и в дальнейшем ее можно использовать в приложении:
Строка куки принимает до шести различных параметров: имя куки, значение, срок
окончания действия (expires), путь (path), домен (domain) и secure. Выше
использовались только два параметра: имя куки и значение. То есть в случае со
строкой "login=tom32;" куки имеет имя login и значение tom32.
219
Но подобная куки имеет очень ограниченный срок жизни: если явным образом не
установить срок действия, то кука будет удалена с закрытием браузера. Подобная
ситуация, возможно, идеальна для тех случаев, когда необходимо удалять всю
информацию после завершения работы с веб-приложением и закрытия браузера.
Однако данное поведение не всегда подходит.
И в этом случае нам надо установить параметр expires, то есть срок действия куков:
1 [Link] = "login=tom32;expires=Mon, 31 Aug 2015 00:00:00 GMT;";
То есть срок действия куки login истекает в понедельник 31 августа 2015 года в 00:00.
Формат параметра expires очень важен. Однако его можно сгенерировать
программно. Для этого мы можем использовать метод toUTCString() объекта Date:
1 var expire = new Date();
2 [Link]([Link]() + 4);
3 [Link] = "login=tom32;expires=" + [Link]() + ";";
В данном случае срок действия куки будет составлять 4 часа.
Если в друг нам надо установить куки для какого-то определенного пути на сайте, то
мы можем использовать параметр path. Например, мы хотим установить куки только
для пути [Link]/home:
[Link] = "login=tom32;expires=Mon, 31 Aug 2015 00:00:00
1 GMT;path=/home;";
В этом случае для других путей на сайте, например, [Link]/shop, эти куки
будут недоступны.
Если на нашем сайте есть несколько доменов, и мы хотим установить куки
непосредственно для определенного домена, тогда можно использовать
параметр domain. Например, у нас на сайте есть поддомен [Link]:
[Link] = "login=tom32;expires=Mon, 31 Aug 2015 00:00:00
1 GMT;path=/;domain=[Link];";
Параметр path=/ указывает, что куки будут доступны для всех директорий и путей
поддомена [Link].
Последний параметр - secure задает использование SSL (SecureSockets Layer) и
подходит для сайтов, использующих протокол https. Если значение этого параметра
равно true, то куки будут использоваться только при установке защищенного
соединения ssl. По умолчанию данный параметр равен false.
220
[Link] = "login=tom32;expires=Mon, 31 Aug 2015 00:00:00
1 GMT;path=/;domain=[Link];secure=true;";
Получение куки
Для простейшего извлечения куки из браузера достаточно обратиться к
свойству [Link]:
1 var expire = new Date();
2 [Link]([Link]() + 4);
3
4 [Link] = "city=Berlin;expires="+[Link]()+";";
5 [Link] = "country=Germany;expires="+[Link]()+";";
6 [Link] = "login=tom32;";
7
8 [Link]([Link]);
Здесь были установлены три куки, и браузер выведет нам все эти куки:
Извлеченные куки не включают параметры expires, path, domain и secure. Кроме
того, сами куки разделяются точкой с запятой, поэтому нужно еще провести
некоторые преобразования, чтобы получить их имя и значение:
1 var cookies = [Link](";");
2 for(var i=0; i<[Link]; i++){
3
4 var parts = cookies[i].split("="),
5 name = parts[0],
6 value = parts[1];
7 [Link]("Имя куки: " + name + "<br/>");
8 [Link]("Значение: " + value + "<br/><br/>");
}
9
Web Storage
221
Последнее обновление: 1.11.2015
Хотя куки позволяют сохранять информацию, они имеют ряд ограничений. Например,
браузер имеет ограничения на размер куков - каждая кука не может превышать 4 кб.
Куки имеют срок действия, после которого удаляются. Куки являются неотъемлемой
чертой протокола HTTP и при каждом запросе к серверу передаются вместе с
запросом на сервер. Однако для работы с куками на стороне клиента в коде javascript
не имеет значения передача куков на сервер. Кроме того, для извлечения
сохраненных куков надо написать некоторую порцию кода.
web
Поэтому в HTML5 была внедрена новая концепция для хранения данных -
storage. Web storage состоит из двух компонентов: session storage и local
storage.
Session storage представляет временное хранилище информации, которая
удаляется после закрытия браузера.
Local storage представляет хранилище для данных на постоянной основе. Данные
из local storage автоматически не удаляются и не имеют срока действия. Эти данные
не передаются на сервер в запросе HTTP. Кроме того, объем local storage составляет в
Chrome и Firefox 5 Mб для домена, а в IE - 10 Mб.
Все данные в web storage представляют набор пар ключ-значение. То есть каждый
объект имеет уникальное имя-ключ и определенное значение.
Для работы с local storage в javascript используется объект localStorage, а для
работы с session storage - объект sessionStorage.
Для сохранения данных надо передать в метод setItem() объекта localStorage:
1 [Link]("login", "tom32@[Link]");
В этот метод передаются два значения: ключ и значение сохраняемого объекта.
Если в localStorage уже есть объект с ключом "login", то его значение заменяется
новым.
Для получения сохраненных данных надо вызвать метод getItem():
1 var login = [Link]("login"); //tom32@[Link]
В этот метод передается ключ объекта.
222
Чтобы удалить объект, применяется метод removeItem(), который принимает
ключ удаляемого объекта:
1 [Link]("login");
И для полного удаления всех объектов из localStorage можно использовать
метод clear():
1 [Link]();
С сохранением простых объектов все просто, однако при этом надо учитывать, что
данные в localStorage сохраняются в виде строки:
1 [Link]("age", 23);
2 var age = [Link]("age");
3 age=parseInt(age)+10;
4 [Link](age); //33
Если в данном случае не преобразовать значение к числу с помощью parseInt(), то
age будет действовать как строка.
Трудности могут возникнуть с сохранением сложных объектов:
var user ={
1
name: "Tom",
2
age: 23,
3
married: false
4
};
5
6
[Link]("user", user);
7
var savedUser = [Link]("user");
8
[Link](savedUser); //[object Object]
9
[Link]([Link]); // undefined - savedUser - строка, а не
10
объект
В этом случае нам надо использовать сериализацию в формат JSON:
var user ={
1
name: "Tom",
2
age: 23,
3
married: false
4
};
5
6
[Link]("user", [Link](user));
7
var savedUser = [Link]([Link]("user"));
8
[Link]([Link] + " " + [Link] +" " + [Link]); // T
9
23 false
223
И в завершении надо сказать, что в некоторых браузерах с помощью специальных
инструментов мы можем увидеть сохраненные объекты в local storage. Например, в
Google Chrome:
Коллекции и итераторы
Итераторы
Последнее обновление: 09.04.2018
Итераторы применяются для организации последовательного доступа к элементам
коллекции - массивам, объектам Set и Map. Итераторы предоставляют метод next(),
который возвращает два значения: value и done. value хранит собственно значение
текущего перебираемого элемента. А свойство done указывает, есть ли еще в
коллекции объекты, доступные для перебора.
Некоторые методы коллекций возвращают итераторы. Например, метод entries(),
который есть у коллекций Array, Set, Map:
1 let users = ["Tom", "Bob", "Sam"];
2 let items = [Link]();
3 [Link]([Link]());
Метод next возвратит следующий объект на консоль:
{value: Array(2), done: false}
done: false
value: Array(2)
0: 0
1: "Tom"
length: 2
__proto__:Array(0)
__proto__:Object
Здесь мы видим, что свойство done имеет значение false, так как мы перебрали
только один элемент в множестве, и там еще есть два элемента.
224
Свойство value представляет массив из двух значений. Первое значение
представляет ключ или индекс элемента массива, а второй элемент - значение по
этому индексу. имеет ключ и значение.
Соответственно мы можем организовать и перебор всей коллекции:
1 let users = ["Tom", "Bob", "Sam"];
2 let items = [Link]();
3 var result = [Link]();
4
5 while([Link] === false){
6 [Link]([Link][0], [Link][1]);
7 result = [Link]();
8 }
Консольный вывод:
0 "Tom"
1 "Bob"
2 "Sam"
Но в этом нет смысла, поскольку все коллекции, возвращающие итераторы,
поддерживают перебор с помощью цикла for...of, который как раз и использует
итератор для получения элементов:
1 let users = ["Tom", "Bob", "Sam"];
2 for(let val of users)
3 [Link](val);
Если мы хотим извлечь еще и индекс элемента в массиве, то мы можем использовать
для перебора итератор из entries():
1 let users = ["Tom", "Bob", "Sam"];
2 for(let user of [Link]()){
3 [Link](user[0], user[1]);
4 }
Консольный вывод:
0 "Tom"
1 "Bob"
2 "Sam"
Генераторы
Последнее обновление: 09.04.2018
225
Генераторы представляют особый тип функции, которые используются для генерации
значений. Для определения генераторов применяется символ звездочки *, который
ставится после ключевого слова function. Например, определим простейший
генератор:
1 function* getNumber(){
2 yield 5;
3 }
4 let numberGenerator = getNumber();
5 let next = [Link]();
6 [Link](next);
Функция getNumber представляет генератор. Функция генератора возвращает
итератор. Для получения значения из генератора применяется оператор yield. То есть
фактически в данном случае генератор генерирует число 5.
Далее с помощью вызова этой функции создается объект итератора в виде
переменной numberGenerator. Используя этот объект, мы можем получать из
генератора значения.
Для перехода к следующему значению применяется метод next(). Если мы посмотрим
на консольный вывод, то мы увидим, что данный метод возвращает следующие
данные:
{value: 5, done: false}
То есть по сути возвращается объект, свойство value которого содержит собственно
сгенерированное значение. А свойство done указывает, достигли ли мы конца
генератора.
Теперь изменим код:
1 function* getNumber(){
2 yield 5;
226
3 }
4 let numberGenerator = getNumber();
5 let next = [Link]();
6 [Link](next);
7 next = [Link]();
8 [Link](next);
Здесь обращение к методу next() происходит два раза:
{value: 5, done: false}
{value: undefined, done: true}
Но функция генератора getNumber генерирует только одно значение - число 5.
Поэтому при повторном вызове свойство value будет иметь значение undefined, а
свойство done - true, то есть работа генератора завершена.
Генератор может создавать множество значений:
1 function* getNumber(){
2 yield 5;
3 yield 25;
4 yield 125;
5 }
6 let numberGenerator = getNumber();
7 [Link]([Link]());
8 [Link]([Link]());
[Link]([Link]());
9
[Link]([Link]());
10
Консольный вывод:
{value: 5, done: false}
{value: 25, done: false}
{value: 125, done: false}
{value: undefined, done: true}
227
То есть при первом вызове метода next() из итератора извлекается значение,
которое идет после первого оператора yield, при втором вызове метода next() -
значение после второго оператора yield и так далее.
Поскольку для получения значений применяется итератор, то мы можем использовать
цикл for...of:
1 function* getNumber(){
2 yield 5;
3 yield 25;
4 yield 125;
5 }
6 let numberGenerator = getNumber();
7
8 for(let num of numberGenerator){
[Link](num);
9
}
10
Консольный вывод:
25
125
Генератор необязательно содержит только определение операторов yield. Он также
может содержать более сложную логику.
С помощью генераторов удобно создавать бесконечные последовательности:
1 function* points(){
2
3 let x = 0;
4 let y = 0;
while(true){
5
yield {x:x, y:y};
6
x += 2;
7
228
8 y += 1;
9 }
10 }
11 let pointGenerator = points();
12
13 [Link]([Link]().value);
14 [Link]([Link]().value);
[Link]([Link]().value);
15
Консольный вывод:
{x: 0, y: 0}
{x: 2, y: 1}
{x: 4, y: 2}
Передача данных в генератор
С помощью next() можно передать в генератор данные.
1 function* getNumber(){
2 let n = yield 5;
3 [Link]("n:", n);
4 let m = yield 25 * n;
5 [Link]("m:", m);
6 yield 125 * m;
7 }
8 let numberGenerator = getNumber();
9
[Link]([Link]().value);
10
[Link]([Link](2).value);
11
[Link]([Link](3).value);
12
Консольный вывод:
5
229
n: 2
50
m: 3
375
При втором вызове метода next():
1 [Link](2).value
Мы можем получить переданные через него данные, присвоив
результат первого оператора yield:
1 let n = yield 5;
То есть здесь переменная n будет равна 2, так как в метод next() передается число 2.
Далее мы можем использовать это значение, например, для генерации нового
значения:
1 let m = yield 25 * n;
Соответственно, переменная m получить значение, переданное через третий вызов
метода next(), то есть число 3.
Инициализация генератора
Есть также другой способ передачи данных в генератор, когда мы передаем
некоторые данные в саму функцию генератора, то есть фактически инициализируем
генератор некоторыми начальными данными:
1 function* takeItem(arr){
2 for(var i=0; i < [Link]; i++){
3 yield arr[i];
}
4
}
5
var users = ["Tom", "Bob", "Sam", "Alice", "Kate", "Ann"];
6
7
var userGenerator = takeItem(users);
8
9
230
10 var timer = setInterval(function(){
11 var user = [Link]();
12 if([Link]){
13 clearInterval(timer);
14 [Link]("The End...");
15 } else{
16 [Link]([Link]);
}
17
}, 500);
18
В данном случае в генератор передается массив, который используется для
генерации значений в таймере.
Множества Set
Последнее обновление: 09.04.2018
Множества (sets) представляют структуру данных, которая может хранить только
уникальные значения. В JavaScript функционал множества опредляет объект Set. Для
создания множества применяется конструктор этого объекта:
1 let mySet = new Set();
Также можно передать в конструктор массив значений, которыми будет
инициализировано множество:
1 let arr = [1, 1, 2, 3, 4, 5, 2, 4];
2 let numbers = new Set(arr);
3 [Link](numbers); // Set(5) {1, 2, 3, 4, 5}
231
В данном случае в множество передаются данные из массива. Однако поскольку
множество может хранить только уникальные значения, то при его создании
повторяющиеся значения, которые есть в массиве, удаляются.
Для проверки количества элементов можно использовать свойство size.
1 let arr = [1, 1, 2, 3, 4, 5, 2, 4];
2 let numbers = new Set(arr);
3 [Link]([Link]); // 5
Добавление
Для добавления применяется метод add(). Его результатом является измененное
множество:
1 let numbers = new Set();
2 [Link](1);
3 [Link](3);
4 [Link](5);
5 [Link](3); // не добавляется
6 [Link](1); // не добавляется
[Link](numbers); // Set(3) {1, 3, 5}
7
При этом, поскольку множество хранит только уникальные значения, то добавление
элементов, которые уже в нем есть, не имеет смысла.
Так как метод add возвращает ссылку на это же множество, то мы можем вызывать
методы по цепочке:
1 let numbers = new Set();
2 [Link](1).add(3).add(5);
3 [Link](numbers); // Set(3) {1, 3, 5}
Удаление
Для удаления элементов применяется метод delete():
1 let numbers = new Set();
2 [Link](1).add(3).add(5);
3 [Link](3);
232
4 [Link](numbers); // Set(2) {1, 5}
Причем данный метод возвращает булевое значение: true - если элемент удален и
false - если удаление не произошло (например, когда удаляемого элемента нет в
множестве):
1 let numbers = new Set();
2 [Link](1).add(3).add(5);
3
4 let isDeleted = [Link](3);
5 [Link](isDeleted); // true
6 isDeleted = [Link](54);
7 [Link](isDeleted); // false
Если необходимо удалить вообще все элементы из множества, то применяется
метод clear():
1 let numbers = new Set();
2 [Link](1).add(3).add(5);
3 [Link]();
4 [Link](numbers); // Set(0) {}
Проверка наличия элемента
Если нужно проверить, если ли элемент в множестве, то используется метод has().
Если элемент есть, то метод возвращает true, иначе возвращает false:
1 let numbers = new Set();
2 [Link](1).add(3).add(5);
3 [Link]([Link](3)); // true
4 [Link]([Link](32)); // false
Перебор множества
Для перебора элементов множества применяется метод forEach():
1 let arr = [1, 2, 3, 5];
2 let numbers = new Set(arr);
233
3
4 [Link](function(value1, value2, set){
5 [Link](value1);
6 })
Для совместимости с массивами, которые тоже имеют метод forEach, в данный метод
передается функция обратного вызова, которая принимает три параметра.
Непосредственно для множества первый и второй параметры представляют текущий
перебираемый элемент, а третий параметр - перебираемое множество.
Также для перебора множества можно использовать цикл for...of:
1 let numbers = new Set([1, 2, 3, 5]);
2
3 for(n of numbers){
4 [Link](n);
5 }
Map
Последнее обновление: 09.04.2018
Map или карта (отображение, словарь) представляет структуру данных, где каждый
элемент имеет ключ и значение. Ключи в рамках карты являются уникальными, то
есть с одним ключом может быть сопоставлен только один элемент. Для создания
карты применяется конструктор объекта Map:
1 let myMap = new Map();
Также можно инициализировать карту начальными значениями. Для этого в
конструктор передается массив, элементы которого представляют массивы из двух
элементов - первый элемент будет выступать в качестве ключа, а второй - в качестве
значения:
234
1 let myMap = new Map([[1, "a"], [2, "b"], [3, "c"]]);
2 [Link](myMap); // Map(3) {1 => "a", 2 => "b", 3 => "c"}
В данном случае числа 1, 2, 3 являются ключами, а строки "a", "b", "c" - значениями.
При этом ключи и значения необзательно должны быть одного типа:
1 let myMap = new Map([["a", 1], [2, "b"], ["c", true]]);
2 [Link](myMap); // Map(3) {"a" => 1, 2 => "b", "c" => true}
Добавление и изменение элементов
Для добавления или изменения значения применяется метод set():
1 let myMap = new Map([[1, "a"], [2, "b"], [3, "c"]]);
2 [Link](4, "d"); // добавление элемента
3 [Link](2, "v"); // изменение элемента
4 [Link](myMap); // Map(4) {1 => "a", 2 => "v", 3 => "c", 4 => "d"}
Первый параметр метода set() представляет ключ, а второй параметр - значение
элемента. Если по такому ключу нет элементов, то добавляется новый элемент. Если
ключ уже есть, то уже имеющийся элемент изменяет свое значение.
Получение элементов
Для получения элемента по ключу применяется метод get(), в который передается
ключ элемента:
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2 [Link]([Link](2)); // Bob
3 [Link]([Link](7)); // undefined
Если map не содержит элемента по заданному ключу, то метод возвращает undefined.
Чтобы избежать возвращения undefined мы можем проверить наличие элемента по
ключу с помощью метода has(). Если элемент по ключу имеется, то метод
возвращает true, иначе возвращается false:
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2 [Link]([Link](2)); // true
235
3 [Link]([Link](7)); // false
Удаление элементов
Для удаления одного элемента по ключу применяется метод delete():
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2 [Link](2);
3 [Link](myMap); // Map(2) {1 => "Tom", 3 => "Sam"}
Для удаления всех элементов используется метод clear():
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2 [Link]();
3 [Link](myMap); // Map(0) {}
Перебор элементов
Для перебора элементов используется метод forEach:
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2
3 [Link](function(value1, value2, map){
4 [Link](value2, value1);
5 })
Метод forEach в качестве параметра получает функцию обратного вызова, которая
имеет три параметра. Первый и второй параметры - это соответственно значение и
ключ текущего перебираемого элемента, а третий параметр - перебираемый объект
Map.
Консольный вывод данного примера:
1 Tom
2 Bob
3 Sam
Также для перебора объекта Map можно использовать цикл for...of:
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
236
2
3 for(item of myMap){
4 [Link](item[0], item[1]);
5 }
Каждый элемент из Map помещается в переменную item, которая в свою очередь
представляет массив. Первый элемент этого массива - ключ, а второй элемент -
значение элемента.
Также объект Map имеет два дополнительных метода: keys() позволяет перебрать
только ключи и values() позволяет перебирать значения элементов. Оба метода
возвращают итераторы, поэтому для перебоа ключей и значений по отдельности
также можно использовать цикл for...of:
1 let myMap = new Map([[1, "Tom"], [2, "Bob"], [3, "Sam"]]);
2
3 for(item of [Link]()){
4 [Link](item);
5 }
6 for(item of [Link]()){
7 [Link](item);
}
8
WeakSet и WeakMap
Последнее обновление: 09.04.2018
WeakSet
Объект WeakSet во многом похож на обычное множество. Он также может хранить
только уникальные значения, но каждый его элемент должен представлять объект.
237
Для создания объекта WeakSet используется его конструктор, в который можно
передать начальные значения:
1 // пустой WeakSet
2 let weakSet1 = new WeakSet();
3 // инициализация начальными значениями
4 let weakSet2 = new WeakSet([{name:"Tom"}, {age: 34}]);
Для инициализации как в случае с объектом Set в конструктор передается массив, но
данный массив содержит именно объекты, а не скалярные значения, типа чисел или
строк.
Для добавления данных в WeakSet применяется метод add():
1 let weakSet = new WeakSet();
2 [Link]({lang: "JavaScript"});
3 [Link]({lang: "TypeScript"});
4 // [Link](34); // так нельзя - 34 - число, а не объект
5 [Link](weakSet); // {{lang: "JavaScript"}, {lang: "TypeScript"}}
Причем опять же добавить мы можем только объект, а не скалярные значения типа
чисел или строк.
Для удаления применяется метод delete(), в который передается ссылка на
удаляемый объект:
1 let weakSet = new WeakSet();
2 var js = {lang: "JavaScript"};
3 var ts = {lang: "TypeScript"};
4 [Link](js);
5 [Link](ts);
6
7 [Link](js);
8
[Link](weakSet); // {{lang: "TypeScript"}}
9
238
Если надо проверить, имеется ли объект в WeakSet, то можно использовать
метод has(), который возвращает true при наличии объекта:
1 var js = {lang: "JavaScript"};
2 var ts = {lang: "TypeScript"};
3 var java = {lang: "Java"};
4 let weakSet = new WeakSet([js, ts]);
5 [Link]([Link](ts)); // true
6 [Link]([Link](java)); // false
WeakMap
WeakMap представляет развитие коллекции Map. Особенностью WeakMap является то,
что все ее элементы должны представлять объекты. При этом объектами должны
быть как ключи, так и значения.
Создание WeakMap:
1 // пустой WeakMap
2 let weakMap1 = new WeakMap();
3
4 // WeakMap с инициализацией данными
5 var key1 = {key:1};
6 var key2 = {key:2};
7 var value1 = {name: "Tom"};
8 var value2 = {name: "Sam"};
9
let weakMap2 = new WeakMap([[key1, value1], [key2, value2]]);
10
Для получения объектов по ключу из WeakMap применяется метод get():
1 var key1 = {key:1};
2 var key2 = {key:2};
3 var value1 = {name: "Tom"};
var value2 = {name: "Sam"};
4
5
239
6 let weakMap2 = new WeakMap([[key1, value1], [key2, value2]]);
7 [Link]([Link](key1)); // {name: "Tom"}
Для добавления новых объектов или изменения старых применяется метод set():
1 var key1 = {key:1};
2 var key2 = {key:2};
3 var value1 = {name: "Tom"};
4 var value2 = {name: "Sam"};
5
6 let weakMap2 = new WeakMap([[key1, value1]]);
7 [Link](key2, value2);
8 [Link](key1, {name: "Kate"});
[Link]([Link](key1)); //{name: "Kate"}
9
[Link]([Link](key2)); //{name: "Sam"}
10
Чтобы проверить наличие элемента по определенному ключу, применяется
метод has(), который возвращает true при наличии элемента:
1 var key1 = {key:1},
2 key2 = {key:2};
3 var value1 = {name: "Tom"},
4 value2 = {name: "Sam"};
5
6 let weakMap2 = new WeakMap([[key1, value1]]);
7 [Link]([Link](key1)); // true
[Link]([Link](key2)); // false
8
Для удаления элемента по ключу применяется метод delete():
1 var key1 = {key:1},
2 key2 = {key:2};
3 var value1 = {name: "Tom"},
240
4 value2 = {name: "Sam"};
5
6 let weakMap2 = new WeakMap([[key1, value1], [key2, value2]]);
7 [Link]([Link](key1)); // true
8 [Link](key1);
9 [Link]([Link](key1)); // false
Ajax
Последнее обновление: 1.11.2015
Современные веб-приложение, как правило, разделяются на две части: клиент и
сервер. Клиент представляет собой веб-страницу с кодом JavaScript. К серверным
технологиям относятся PHP, Ruby, [Link], [Link] и т.д., которые получают запрос от
клиента, обрабатывают и отправляют в ответ результат обработки.
Ajax представляет технологию для отправки запросов к серверу из клиентского кода
JavaScript без перезагрузки страницы. Сам термин расшифровывается как
Asynchronous JavaScript And XML. То есть изначально AJAX предполагал асинхронное
взаимодействие клиента и сервера посредством данных в формате XML. Хотя сейчас
XML во многом вытеснил формат JSON. В любом случае AJAX революционизировал веб-
среду, позволив создавать динамичные отзывчивые веб-приложения.
Поскольку Ajax предполагает взаимодействие клиента и сервера, то для работы с Ajax
и в частности этой главы необходим локальный веб-сервер. Это может быть любой
веб-сервер: Apache, IIS и т.д.
Объект XMLHttpRequest
Для создания приложений, использующих Ajax, применяются различные способы. Но
самым распространенным способом является использование
объекта XMLHttpRequest:
1 var request = new XMLHttpRequest();
241
После создания объекта XMLHttpRequest можно отправлять запросы к серверу. Но для
начала надо вызвать метод open() для инициализации:
1 [Link]("GET", "[Link] false);
Метод open() принимает три параметра: тип запроса (GET, POST, HEAD, PUT), адрес
запроса и третий необязательный параметр - логическое значение true или false,
указывающее, будет ли запрос осуществляться в асинхронном режиме. То есть в
данном случае запрос будет иметь тип GET, он будет направляться по
адресу "[Link] в синхронном режиме, так как стоит значение false
(для асинхронного режима указывается значение true).
Синхронный и асинхронный режим отличаются тем, что запрос в синхронном режиме
пока запрос не выполнится, остальной код javascript не может выполняться. По
умолчанию, если третий параметр не используется, то запрос отправляется в
асинхронном режиме, что позволяет параллельно с выполнением запроса выполнять
также и другой код javascript. И в большинстве случаев, как правило, используется
именно асинхронный режим.
Кроме того, метод open() может принимать еще два параметра: логин и пароль
пользователя, если для выполнения запроса нужна аутентификация.
[Link]("GET", "[Link] true, "login",
1 "password");
После инициализации запроса методом open() необходимо отправить запрос с
помощью метода send():
1 [Link]();
Свойства XMLHttpRequest
Объект XMLHttpRequest имеет ряд свойств, которые позволяют проконтролировать
выполнение запроса:
status: содержит статусный код ответа HTTP, который пришел от сервера. С
помощью статусного кода можно судить об успешности запроса или об
ошибках, которые могли бы возникнуть при его выполнении. Например,
статусный код 200 указывает на то, что запрос прошел успешно. Код 403
говорит о необходимости авторизации для выполнения запроса, а код 404
сообщает, что ресурс не найден и так далее.
statusText: возвращает текст статуса ответа, например, "200 OK"
responseType: возвращает тип ответа. Есть следующие типы:
242
o ""
o "arraybuffer"
o "blob"
o "document"
o "json"
o "text"
response: возвращает ответ сервера
responseText: возвращает текст ответа сервера
responseXML: возвращает xml, если ответ от сервера в формате xml
Например, выполним запрос к текстовому файлу, который находится на локальном
веб-сервере. Для выполнения ajax-запросов потребуется запущенный локальный веб-
сервер, на котором будет лежать файл [Link], в котором будет содержаться одна
строка: "Привет мир".
Код веб-страницы (пусть она называется [Link]) будет следующим:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
7
<script>
8
var request = new XMLHttpRequest();
9
[Link]("GET", "[Link] false);
10
[Link]();
11
var status = [Link];
12 if(status==200)
13 [Link]("Текст ответа: " + [Link])
14 else if(status==404)
243
15
[Link]("Ресурс не найден")
16
else
17
[Link]([Link])
18
</script>
19
</body>
20
</html>
21
И после загрузки страницы выполнится ajax-запрос к
ресурсу [Link] Но важно отметить, что получение статуса сразу
после вызова метода [Link]() будет работать только для синхронного запроса.
Асинхронные запросы
Хотя синхронные запросы вполне работают и их можно использовать, но в то же
время их рекомендуется избегать. Поскольку нередко запрос может занять
продолжительное время, то это может заблокировать выполнение остального кода и
работу с html-страницей до окончания выполнения запроса. Поэтому рекомендуется
использовать преимущественно асинхронные запросы.
Работа с асинхронными запросами чуть более сложна, чем с синхронными, поскольку
нам надо еще обработать событие readystatechange объекта XMLHttpRequest.
При асинхронном запросе объект XMLHttpRequest использует
свойство readyState для хранения состояния запроса. Состояние запроса
представляет собой число:
0: объект XMLHttpRequest создан, но метод open() еще не был вызван для
инициализации объекта
1: метод open() был вызван, но запрос еще не был отправлен методом send()
2: запрос был отправлен, заголовки и статус ответа получены и готовы к
использованию
3: ответ получен от сервера
4: выполнение запроса полностью завершено (даже если получен код ошибки,
например, 404)
244
Событие readystatechange возникает каждый раз, когда изменяется значение
свойства readyState. Например, выполним асинхронный запрос:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta charset="utf-8" />
5
</head>
6
<body>
7
8
<script>
9 var request = new XMLHttpRequest();
10
11 function reqReadyStateChange() {
12 if ([Link] == 4) {
13 var status = [Link];
14 if (status == 200) {
15 [Link]([Link]);
16 } else {
17 [Link]("Ответ сервера " + [Link]);
}
18
}
19
}
20
21
[Link]("GET", "[Link]
22
[Link] = reqReadyStateChange;
23
[Link]();
24
</script>
25
</body>
26 </html>
27
245
Кроме обработки события readystatechange для получения ответа сервера можно
также обрабатывать событие load, которое возникает после выполнения запроса. Его
использование аналогично:
1
var request = new XMLHttpRequest();
2
3
function responceLoad() {
4 if ([Link] == 4) {
5 var status = [Link];
6 if (status == 200) {
7 [Link]([Link]);
8 } else {
9 [Link]("Ответ сервера " + [Link]);
10 }
11 }
}
12
13
[Link]("GET", "[Link]
14
[Link] = responceLoad;
15
[Link]();
16
Отправка данных
Последнее обновление: 1.11.2015
Принцип отправки данных может отличаться в различных ситуациях. Рассмотрим эти
ситуации.
246
Отправка GET-запроса
GET-запрос характеризуется тем, что данные могут отправляться в строке запроса:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<div id="output"></div>
7
<script>
8
// объект для отправки
9
var user = {
1
name: "Tom",
0
age: 23
1
1 };
1
2 var request = new XMLHttpRequest();
1 function reqReadyStateChange() {
3
if ([Link] == 4) {
1
var status = [Link];
4
if (status == 200) {
1
5 [Link]("output").innerHTML=[Link]
xt;
1
}
6
}
1
7 }
1 // строка с параметрами для отправки
8 var body = "name=" + [Link] + "&age="+[Link];
1 [Link]("GET", "[Link]
9
[Link] = reqReadyStateChange;
2
[Link]();
0
247
2
1
2
2
2
3
2
4
2
5
</script>
2
</body>
6
</html>
2
7
2
8
2
9
3
0
3
1
Для отправки берем свойства объекта user и формируем из их значений сроку с
параметрами: "name=" + [Link] + "&age="+[Link]. Затем эта строка
добавляется к строке запроса в методе open("GET",
"[Link]
Предполагается, что данные отправляются скрипту на языке php [Link],
который может иметь, например, следующее содержание:
1 <?php
2 $name = "Не известно";
3 $age = "Не известно";
if(isset($_GET['name'])) $name = $_GET['name'];
4
if (isset($_GET['age'])) $age = $_GET['age'];
5
echo "Ваше имя: $name <br> Ваш возраст: $age";
248
6
?>
7
Конкретная технология стороны сервера тут не важна. И в качестве тестирования
можно взять любую другую технологию. Например, [Link] MVC. Метод контроллера
в [Link] MVC, который принимает данные, мог бы выглядеть следующим образом:
1 public string PostData(string name, int age)
2 {
3 return "Ваше имя: "+name +"; Ваш возраст: "+ age;
4 }
Кодирование параметров
Все отправляемые в GET-запросе параметры разделяются знаком амперсанда(&). Но
что, если какой-нибудь параметр имеет знак амперсанда. Например,
1 var user = {
2 name: "Tom&Tim",
3 age: 23
4 };
5 // строка с параметрами для отправки
6 var body = "name=" + [Link] + "&age="+[Link];
В этом случае при получении параметров скрипт на стороне сервера может
неправильно обработать данные и неправильно извлечь параметры. Поэтому, чтобы
кодировать все передаваемые данные, нужно применять
функцию encodeURIComponent():
var body = "name=" + encodeURIComponent([Link]) +
1 "&age="+encodeURIComponent([Link]);
При этом строка "Tom&Tim" будет кодирована в следующую строку: "Tom%26Tim".
При необходимости мы можем выполнить обратное декодирование с помощью
функции decodeURIComponent():
1 var encodeName = encodeURIComponent([Link]); // Tom%26Tim
2 var decodeName = decodeURIComponent(encodeName); // Tom&Tim
249
POST-запросы
Отправка данных в POST-запросах будет немного отличаться:
1 var user = {
2 name: "Tom",
3 age: 23
4 };
5
6 var request = new XMLHttpRequest();
function reqReadyStateChange() {
7
if ([Link] == 4 && [Link] == 200)
8
[Link]("output").innerHTML=[Link];
9
}
10
var body = "name=" + [Link] + "&age="+[Link];
11
[Link]("POST", "[Link]
12
[Link]('Content-Type', 'application/x-www-form-
13 urlencoded');
14 [Link] = reqReadyStateChange;
15 [Link](body);
Для отправки данных методом POST надо установить заголовок Content-Type с
помощью метода setRequestHeader(). В данном случае заголовок имеет
значение application/x-www-form-urlencoded.
Отправка форм. FormData
Начиная со спецификации XMLHttpRequest2 в JavaScript появился новый объект
- FormData, который позволяет сериализовать данные формы для ее последующей
отправки. При этом нам даже необязательно создавать форму в коде html, мы можем
создать ее динамически в JavaScript:
1 var formData = new FormData();
2 [Link]('name', 'Tom');
3 [Link]('age', 23);
4
var request = new XMLHttpRequest();
250
5
function reqReadyStateChange() {
6
if ([Link] == 4 && [Link] == 200)
7
[Link]("output").innerHTML=[Link];
8
}
9
10
[Link]("POST", "[Link]
11
[Link] = reqReadyStateChange;
12 [Link](formData);
13
Для добавления данных у объекта FormData используется
метод append('имя_параметра', значение). При этом никакие заголовки указывать
не надо.
Также мы можем определить форму в html и использовать ее для отправки:
1 <!DOCTYPE html>
2 <html>
3 <head>
<meta charset="utf-8" />
4
</head>
5
<body>
6
<div id="output"></div>
7
<form name="user" action="[Link]
8
<input type="text" name="username" placeholder="Введите имя" /><br/>
9
<input type="text" name="age" placeholder="Введите возраст" /><br/>
1
<input type="submit" name="submit" value="Отправить" />
0
</form>
1
1 <script>
1 // получаем объект формы
2 var form = [Link];
1 // прикрепляем обработчик кнопки
3
[Link]("click", sendRequest);
1
251
4
1 // обработчик нажатия
5 function sendRequest(event){
1
6
[Link]();
1
var formData = new FormData(form);
7
1
8 var request = new XMLHttpRequest();
1
9
[Link]("POST", [Link]);
2
0
[Link] = function () {
2
1 if ([Link] == 4 && [Link] == 200)
[Link]("output").innerHTML=[Link]
2
xt;
2
}
2
3 [Link](formData);
2 }
4 </script>
2 </body>
5
</html>
2
6
2
7
2
8
2
9
3
0
3
1
252
3
2
3
3
3
4
3
5
3
6
3
7
Для сериализации всех полей формы нам достаточно передать объект формы в
конструктор FormData: var formData = new FormData(form);
Отправка данных в формате json
Для отправки данных в формате json нам необходимо установить соответствующий
заголовок и сериализовать данные с помощью метода [Link]:
1 // объект для отправки
2 var user = {
3 username: "Tom",
age: 23
4
};
5
var json = [Link](user);
6
var request = new XMLHttpRequest();
7
[Link]("POST", "[Link]
8
[Link]('Content-type', 'application/json; charset=utf-8');
9
[Link] = function () {
1
if ([Link] == 4 && [Link] == 200)
0
[Link]("output").innerHTML=[Link];
1
1 }
1 [Link](json);
2
253
1
3
1
4
Promise в Ajax-запросах
Последнее обновление: 10.04.2018
Как видно из примеров прошлых тем для создания ajax-запросов используются
фактически повторяющиеся вызовы, отличающиеся лишь деталями - строкой запроса,
функциями обработки ответа. И вполне было бы не плохо создать для всех действий,
связанных с асинхронным ajax-запросом, создать какую-то общую абстракцию и затем
использовать ее при следующих обращениях к серверу.
Для создания дополнительного уровня абстракции в данном случае удобно применять
объект Promise, который обертывает асинхронную операцию в один объект,
который позволяет определить действия, выполняющиеся при успешном или
неудачном выполнении этой операции.
Инкапсулируем асинхронный запрос в объект Promise:
1 function get(url) {
2 return new Promise(function(succeed, fail) {
3 var request = new XMLHttpRequest();
4 [Link]("GET", url, true);
5 [Link]("load", function() {
6 if ([Link] < 400)
7 succeed([Link]);
8 else
9 fail(new Error("Request failed: " + [Link]));
10 });
11 [Link]("error", function() {
12 fail(new Error("Network error"));
13 });
14 [Link]();
15 });
16 }
Метод get получает в качестве параметра адрес ресурса сервера и возвращает объект
Promise. Конструктор Promise в качестве параметра принимает функцию обратного
254
вызова, которая в свою очередь принимает два параметра - две функции: одна
выполняется при успешной обработке запроса, а вторая - при неудачной.
Допустим, на сервере будет размещен файл [Link] со следующим содержимым:
1 [
2 {
3 "name": "Tom",
4 "age": 34
5 }, {
6 "name": "Sam",
7 "age": 32
8 }, {
9 "name": "Bob",
10 "age": 26
11 }
12 ]
Теперь вызовем метод get для осуществления запроса к серверу:
1 get("[Link] {
2 [Link](text);
3 }, function(error) {
4 [Link]("Error!!!");
5 [Link](error);
6 });
Для обработки результата объекта Promise вызывается метод then(), который
принимает два параметра: функцию, вызываемую при успешном выполнении запроса,
и функцию, которая вызывается при неудачном выполнении запроса.
Метод then() также возвращает объект Promise. Поэтому при необходимости мы
можем применить к его результату цепочки вызовов метода
then: get().then().then().... Например:
1 get("[Link] {
2 [Link](response);
3 return [Link](response);
4 }).then(function(data) {
5 [Link](data[0]);
6 });
В данном случае функция в первом вызове метода then получает ответ сервера и
возвращает распарсенные данные в виде массива с помощью функции [Link]().
Функция во втором вызове then получает эти распарсенные данные, то есть массив, в
виде параметра (возвращаемое значение предудыщего then является параметром для
последующего then). Затем первый элемент массива выводится на консоль.
255
Для обработки ошибок мы мы можем использовать метод catch(), в который
передается функция обработки ошибок:
1 get("[Link] {
2 [Link](response);
3 return [Link](response);
4 }).then(function(data) {
5 [Link](data[0]);
6 }).catch(function(error){
7 [Link]("Error!!!");
8 [Link](error);
9 });
Подобным образом через Promise можно было бы отправлять данные на сервер:
function post(url, requestuestBody) {
1
return new Promise(function(succeed, fail) {
2
var request = new XMLHttpRequest();
3
[Link]("POST", url, true);
4
[Link]('Content-Type', 'application/x-www-form-
5
urlencoded');
6
[Link]("load", function() {
7
if ([Link] < 400)
8
succeed([Link]);
9
else
10
fail(new Error("Request failed: " + [Link]));
11
});
12
[Link]("error", function() {
13
fail(new Error("Network error"));
14
});
15
[Link](requestuestBody);
16
});
17
}
18
19
var user = {
20
name: "Tom&Tim",
21
age: 23
22
};
23
// данные для отправки
24
var params = "name=" + [Link] + "&age="+[Link];
25
26
post("[Link] params).then(function(text) {
27
[Link](text);
28
}, function(error) {
29
[Link](error);
30
});
НазадСодержание
256