Лабораторне заняття 9. Використання JavaScript
Мета роботи: освоїти роботу з мовою програмування JavaScript, підключенням до HTML та використанням готових рішень.
Теоретичні відомості
JavaScript (JS) – динамічна, об'єктно-орієнтована прототипна мова програмування. Найчастіше використовується для створення сценаріїв веб-сторінок, що надає можливість на стороні клієнта взаємодіяти з користувачем, керувати браузером, асинхронно обмінюватися даними з сервером, змінювати структуру та зовнішній вигляд веб-сторінки.
При використанні в рамках технології DHTML JavaScript код включається в HTML-код сторінки і виконується інтерпретатором, вбудованим в браузер. Код JavaScript вставляється в теги <script></script>:
<script> alert("Привіт, світ!"); </script>
Ще одна можливість підключення JavaScript – написати скрипт окремим файлом, та підключити його за допомогою конструкції:
<script src="js/javascriptfile.js"></script>
Скрипти можуть розташовуватися як в області заголовка head, так і в області тіла body.
Структура коду
Інструкції – це синтаксичні конструкції і команди, які виконують певні дії.
Інструкція alert вже була представлена вище. Вона відображає повідомлення «Привіт, світ!» у вигляді діалогового вікна (рис. 3.1).
Рисунок 3.1 – Діалогове вікно alert
В коді може бути стільки інструкцій, скільки потрібно. Інструкції можуть відокремлюватися крапкою з комою. Зазвичай кожну інструкцію записують з нового рядка, щоб код було легше читати.
З часом програми стають все складнішими, тому виникає необхідність додавати коментарі, які б описували, що робить код і чому.
Коментарі можуть розміщуватися в будь-якому місці скрипта. Вони не впливають на його виконання, оскільки при виконанні просто ігноруються.
Однорядкові коментарі починаються з подвійної косої риски //. Частина рядка після // вважається коментарем. Такий коментар може як займати весь рядок, так і бути розміщений після інструкції:
// Цей коментар займає весь рядок
alert('Привіт');
alert('Світ'); // Цей коментар розміщений після інструкції
Багаторядкові коментарі починаються косою рискою із зірочкою /* і закінчуються зірочкою з косою рискою */. Вкладені коментарі не підтримуються! Не може бути /*...*/ всередині /*...*/.
Змінні та константи
Змінна – це іменована область пам’яті для збереження даних. Для створення змінної в JavaScript використовується ключове слово let:
let message;
Тепер можна помістити в неї дані, використовуючи оператор присвоєння:
message = 'Hello';
В JavaScript є два обмеження, що стосуються імен змінних:
- Ім'я змінної має містити тільки літери, цифри або символи $ та _.
- Перший символ не повинен бути цифрою.
Приклади допустимих імен:
let userName;
let test123;
Якщо ім'я містить кілька слів, зазвичай використовується «верблюжа нотація», тобто, слова слідують одне за іншим, де кожне наступне слово починається з великої літери: myVeryLongName.
Регістр має значення. Змінні з іменами apple and Apple – це дві різні змінні.
Нелатинські літери дозволені, але не рекомендуються.
Існує список зарезервованих слів, які не можна використовувати в якості імен змінних, тому що вони використовуються самою мовою. Наприклад: let, class, return і function зарезервовані.
Щоб оголосити константну, використовується const замість let:
const myBirthday = '18.04.1982';
Константи не можна змінити. Спроба зробити це призведе до помилки.
Широко поширена практика використання констант в якості псевдонімів для різних значень, які відомі до початку виконання скрипта, але простіше їх запам’ятати за іменем. Назви таких констант пишуться з використанням великих літер та знаку підкреслення:
const COLOR_ORANGE = "#FF7F00";
Типи даних
Змінна в JavaScript може містити будь-які дані. В один момент там може бути текст, а в іншій – число:
let message = "hello";
message = 123456;
Мови програмування, в яких таке можливо, називаються «динамічно типізованими». Це означає, що типи даних в них є, але змінні не прив'язані до жодного з них.
В JavaScript виділяють вісім типів даних:
1) Числовий тип даних (number) представляє як цілочисельні значення, так і числа з плаваючою точкою:
let n = 123;
n = 12.345;
Крім звичайних чисел, існують так звані спеціальні числові значення, які відносяться до цього типу даних: Infinity, -Infinity і NaN.
Infinity – це математична нескінченність ∞. Її можна отримати в результаті ділення на нуль.
NaN (не число) означає помилку обчислення. Це результат неправильної або невизначеної математичної операції.
Математичні операції в JavaScript «безпечні». Можна робити що завгодно: ділити на нуль, працювати з рядками як з числами і т.д. Скрипт ніколи не зупиниться з фатальною помилкою. В найгіршому випадку ми тримаємо NaN як результат виконання.
2) Тип BigInt був доданий в JavaScript, щоб дати можливість працювати з цілими числами довільної довжини, оскільки тип number не може містити числа більше, ніж 253. Щоб створити значення типу BigInt, необхідно додати n в кінці:
const bigInt = 1234567890123456789012345678901234567890n;
3) Текстовий рядок (string) в JavaScript повинен бути заключений в лапки:
let str = "Привіт";
let str2 = 'Одинарні лапки теж підходять';
let phrase = `Зворотні лапки можуть включати змінні ${str}`;
Подвійні або одинарні лапки є простими, між ними немає різниці в JavaScript. Зворотні лапки мають розширену функціональність – вони дозволяють вбудовувати вирази в рядок, вкладаючи їх в ${...}.
4) Булевий тип (boolean) може приймати тільки два значення: true (правда) і false (неправда):
let nameFieldChecked = true;
let ageFieldChecked = false;
5) Спеціальне значення null не відноситься до жодного з типів, описаних вище. Воно формує окремий тип, який містить тільки значення null. Це просто спеціальне значення, яке представляє собою нічого, порожньо або значення невідоме.
6) Спеціальне значення undefined також стоїть оремо. Воно формує тип з самого себе так само, як і null. Воно означає, що значення не було присвоєно. Якщо змінна оголошена, але їй не присвоєно значення, то її значенням буде рівне undefined.
Зазвичай null використовується для присвоєння змінній порожнього або невідомого значення, а undefined – для перевірок, чи було змінній призначено значення.
7) Тип object (об'єкт) – особливий. Всі інші типи називаються примітивними, тому що їх значеннями можуть бути тільки простими (рядок, число). Об'єкти використовуються для зберігання колекцій даних або більш складних об'єктів.
8) Тип symbol (символ) використовується для створення унікальних ідентифікаторів об'єктів.
Оператор typeof повертає тип аргументу. Це корисно, коли потрібно обробляти значення різних типів по-різному або просто зробити перевірку.
В нього є два варіанти синтаксису:
- Синтаксис оператора: typeof x.
- Синтаксис функції: typeof(x).
Результат виконання однаковий.
Перетворення типів
Найчастіше оператори і функції автоматично перетворюють передані їм значення до потрібного типу.
Наприклад, alert автоматично перетворює будь-яке значення в текстовий рядок. Математичні оператори перетворюють значення в числа.
Однак часто бувають випадки, коли потрібно явно перетворити значення.
Функція String призначена для перетворення значення в текстовий рядок:
let value = true;
value = String(value); // тепер value це рядок "true"
Чисельне перетворення відбувається в математичних функціях і виразах. Наприклад, коли операція ділення / застосовується не до числа:
alert("6" / "2"); // 3, Рядки перетворюються в числа
Функція Number потрібна, щоб явно перетворити значення в число:
let str = "123"; // текстовий рядок
let num = Number(str); // перетворюється в число 123
Якщо рядок не може бути явно перетворений в число, то результатом перетворення буде NaN.
Майже всі математичні оператори виконують чисельне перетворення. Виняток становить оператор +. Якщо один з додатків є рядком, тоді і всі інші додатки перетворюються в рядок.
В такому випадку вони приєднуються один до одного:
alert(1 + '2'); // '12' (рядок справа)
alert('1' + 2); // '12' (рядок зліва)
Логічне перетворення відбувається в логічних операторах, але також може бути виконано явно за допомогою функції Boolean.
Правило перетворення:
- Значення, які є порожніми (0, порожній рядок, null, undefined та NaN) стають рівні false.
- Всі інші значення стають рівні true.
Оператори
Крім основних стандартних операторів (+, -, *, /) JavaScript також має ряд додаткових.
Оператор додавання + додає числа. Якщо одне зі значень рядок – всі інші значення також будуть перетворені в рядок. Однак, якщо перед рядком йде два числа – над ними буде виконана операція додавання:
alert(2 + 2 + '1'); // буде "41", а не "221"
Унарний оператор + перетворює інші типи даних в числовий:
alert(+true); // 1
alert(+""); // 0
let apples = "2";
let oranges = "3";
alert(apples + oranges); // "23", бінарний оператор
alert(+apples + +oranges); // 5
Оператор остачі від ділення %, незважаючи на позначення, ніякого відношення до відсотків не має. Результат a % b – це залишок від ділення a на b.
Оператор піднесення до степеню ** доданий в мову відносно недавно. Для натурального числа b результат a ** b дорівнює a, помноженому на себе b разів.
Оператор працює і для дійсних чисел:
alert(2 ** 3); // 8 (2 * 2 * 2)
alert(8 ** (1/3)); // 2 (корінь кубічний)
Як і в мові C, JavaScript має оператори інкременту (++) та декременту (--).
Оператор кома використовується рідко та є одним із самих незвичних операторів. Оператор кома надає можливість обчислювати кілька виразів, розділяючи їх комою. Кожен вираз виконується, але повертається результат тільки останнього:
let a = (1 + 2, 3 + 4);
alert(a); // 7 (результат 3 + 4)
При використанні операторів порівняння, виконується автоматичне перетворення типів даних:
alert('2' > 1); // true, рядок '2' стає числом 2
alert(true == 1); // true
let a = 0;
alert(Boolean(a)); // false
let b = "0";
alert(Boolean(b)); // true
Однак при переведенні деяких типів стандартний оператор рівності (==) не завжди спрацьовує коректно. Наприклад, коли потрібно відрізнити число 0 та значення false.
В таких випадках використовується оператор строгої рівності (===), який при порівнянні значень не перетворює типи автоматично:
alert(0 == false); // true
alert(0 === false); // false
Взаємодія з користувачем
Функція alert вже була описана вище.
Крім неї використовується ще дві функції, для взаємодії з користувачем у вигляді діалогового вікна:
Функція confirm відображає модальне вікно з текстом питання та двома кнопками: OK та Скасути (рис. 3.2). Повертає результат true, якщо натиснута кнопка OK, в іншому випадку – false:
let isBoss = confirm("Ти тут головний?");
Рисунок 3.2 – Діалогове вікно confirm
Функція prompt приймає два аргументи та відображає діалогове вікно з текстом, полем для введення тексту та кнопками OK/Скасувати (рис. 3.3). Користувач може надрукувати щось в полі введення і натиснути OK. Він також може скасувати введення натиснувши на кнопку «Скасути» або на клавішу Esc. Виклик prompt поверне текст, вказаний в полі для введення, або null, якщо введення скасоване користувачем:
let age = prompt('Скільки тобі років?', 100);
alert(`Тобі ${age} років!`); // Тобі 100 років!
Рисунок 3.3 – Діалогове вікно prompt
Використання умовних операторів, циклів, оператора вибору switch аналогічно синтаксису мові C.
Функції
Доволі часто виникає необхідність повторити певні дії. Наприклад, потрібно вивести повідомлення при відвідуванні веб-сайту на кількох сторінках.
Щоб не писати один і той же код в кількох місцях, використовуються функції. Прикладами вбудованих функцій слугують alert(), confirm(), prompt(). Однак існує можливість створювати і свої власні. Оголошення функції:
function ім’я(параметри) {
...тіло...
}
Виклик функції здійснюється за її іменем:
function showMessage() {
let message = "Привіт, я JavaScript!"; // локальна змінна
alert(message);
}
showMessage(); // виклик функції
Існує можливість передати всередину функції будь-яку інформацію, використовуючи параметри (аргументи функції):
function showMessage(from, text) {
alert(from + ': ' + text);
}
Якщо параметр не вказано, то його значенням стає undefined.
Функція може повертати результат, який буде переданий в код, який її викликав:
function sum(a, b) {
return a + b;
}
let result = sum(1, 2); // 3
Об'єктна модель документа
Об'єктна модель документа (Document Object Model, DOM) – специфікація прикладного програмного інтерфейсу для роботи зі структурованими документами. Визначається консорціумом W3C.
З точки зору об'єктно-орієнтованого програмування, DOM визначає класи, методи та атрибути цих методів для аналізу структури документів та роботи із представленням документів у вигляді дерева (рис 3.4). Все це призначено для того, щоб надати можливість комп'ютерній програмі доступу та динамічної модифікації структури, змісту та оформлення документу.
Рисунок 3.4 – Об’єктна модель документа (DOM)
За допомогою даної моделі JavaScript стає повноцінним інструментом для створення динамічного HTML (DHTML):
- JavaScript може змінити всі HTML-елементи на сторінці;
- JavaScript може змінити всі атрибути HTML на сторінці;
- JavaScript може змінити всі стилі CSS на сторінці;
- JavaScript може реагувати на всі події на сторінці.
DOM дозволяє працювати з елементами та їх вмістом, але для початку потрібно отримати відповідний DOM-об'єкт.
Всі операції з DOM починаються з об'єкта document. Це головна «точка входу» в DOM. З нього можна отримати доступ до будь-якого вузла.
Самі верхні елементи дерева доступні як властивості об'єкта document:
- <html> = document.documentElement
- <body> = document.body
- <head> = document.head
Важливий момент! Скрипт, написаний в розділі head не може використовувати document.body, оскільки розділу body на даний момент ще не існує. Він буде сформований пізніше.
Для отримання доступу до довільного елементу сторінки використовуються спеціальні методи пошуку.
Якщо в елемента є атрибут id, то доступ до нього можна отримати за допомогою виклику document.getElementById(id).
Також в документі існує глобальна змінна з ім'ям, зазначеним в id:
<div id="elem">Елемент</div>
<script>
elem.style.background = 'red';
</script>
Значення id повинно бути унікальним. В документі може бути тільки один елемент з даним id.
Самий універсальний метод пошуку – це elem.querySelectorAll(css), він повертає всі елементи всередині elem, що відповідають даному CSS-селектору:
let elements = document.querySelectorAll('ul > li:last-child');
Метод elem.querySelector(css) повертає перший елемент, який відповідає цьому CSS-селектору:
let chapter = document.querySelector('.chapter');
Властивість innerHTML дозволяє отримати HTML-вміст елемента у вигляді текстового рядка. Також його можна змінювати. Це один з найпотужніших способів змінювати вміст на сторінці:
document.body.innerHTML = 'Новий BODY!';
Атрибут hidden вказує на видимість елемента.
Можна використовувати його в HTML або призначати за допомогою JavaScript, як в прикладі нижче:
<div id="elem">Мигаючий элемент</div>
<script>
setInterval(() => elem.hidden = !elem.hidden, 1000);
</script>
Використовуються наступні методи для роботи з атрибутами елементів:
- elem.hasAttribute(name) – перевіряє наявність атрибута.
- elem.getAttribute(name) – отримує значення атрибута.
- elem.setAttribute(name, value) – встановлює значення атрибута.
- elem.removeAttribute(name) – видаляє атрибут.
Також JavaScript дозволяє взаємодіяти зі стилями:
elem.style.left = '123px';
Для роботи з класами використовуються методи classList:
- elem.classList.add/remove("class") – додати/видалити клас.
- elem.classList.toggle("class") – додати клас, якщо його немає, інакше видалити.
- elem.classList.contains("class") – перевірка наявності класу, повертає true/false.
Для властивостей з декількох слів використовується наступний стиль запису (кожне слово з великої літери):
background-color => elem.style.backgroundColor
z-index => elem.style.zIndex
border-left-width => elem.style.borderLeftWidth
Модифікації DOM – це ключ до створення «живих» сторінок. Можна створювати нові елементи «на льоту» або ж змінювати вже існуючі.
Розглянемо приклад додавання на сторінку повідомлення:
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<p>Текст повідомлення.</p>";
document.body.append(div);
В першому рядку коду створюється елемент div. В другому – задається клас з назвою alert для даного елемента. В третьому рядку формується HTML-код, який буде міститися в даному блоці. Останній рядок відповідає за додавання створеного елементу div до тіла веб-сторінки.
Існують наступні методи додавання вмісту в документ:
- node.append() – додає елементи або текст в кінець елемента node,
- node.prepend() – додає елементи або текст на початок елемента node,
- node.before() – додає елементи або текст перед елементом node,
- node.after() – додає елементи або текст після елемента node,
- node.replaceWith() – замінює node заданим елементом чи текстом.
Приклад використання даних методів показано на рис. 3.5.
Рисунок 3.5 – Приклад використання методів додавання вмісту в документ
Разом з цим існує можливість видаляти зайві елементи в документі. Для цього використовується метод node.remove(). Розглянемо попередній приклад (з виводом повідомлення), в якому додамо видалення цього повідомлення через 1 секунду:
setTimeout(() => div.remove(), 1000);
Метод setTimeout() дозволяє викликати вказану функцію один раз, через визначений проміжок часу.
Поряд з цим, існує функція setInterval(), яка виконує вказану функцію регулярно, через вказаний проміжок часу.
Для того, щоб запустити скрипт не автоматично, а за бажанням користувача, зручно використовувати атрибут onclick посилань:
<a onclick="return myFunction()" href="#">Виконати</a>