lab04
Лабораторная работа 4. Основы JavaScript. Структуры данных. Работа с DOM. Обработка событий
Цель работы
Изучить основы JavaScript. Рассмотреть основные структуры данных в Js. Получить практический опыт работы с DOM и обработкой событий.
Теоретическая часть
Стандарты ECMAScript
ECMAScript (или ES) — это спецификация. То есть набор правил и рекомендаций, которые должны соблюдаться языком, чтобы он считался совместимым с этой спецификацией. JavaScript (или JS) — это язык, который соответствует спецификации ECMAScript.
Так как JavaScript следует спецификации ES, новые фичи описываются именно в ней. Это нам нужно, чтобы понимать, как следить за развитием языка и обновлениями.
Переменные
Переменные в JavaScript хранят значения, которыми оперирует код. Для создания переменных используются ключевые слова var, let и const.
Ключевое слово var считается устаревшим, но всё еще поддерживается в языке. Оно позволяет создавать переменную имеющую область видимости отграниченную функцией или скриптом, в котором она используется.
Ключевое слово let создает переменную с блочной областью видимости – ограничена ближайшими фигурными скобками.
Ключевое слово const работает аналогично let, однако запрещает изменение переменной в последующем коде.
Типы данных
Примитивные типы данных:
- логический (Boolean),
- числа (Number),
- большие числа (BigInt),
- строки (String),
- символы (Symbol),
- undefined,
- null.
Не примитивный тип:
- объект (Object)
Функции Функция — блок кода, который позволяет переиспользовать существующий код. Может иметь входные аргументы и возвращать значение.
Объявление функций (Function Declaration). Обычное объявление. Такую функцию можно вызвать до объявления — благодаря эффекту всплытия (Hoisting).
function greet(name) {
return `Hello ${name}`;
}
Функциональные выражения (Function Expression). Функция будет присвоена переменной и описана без имени. Такую функцию нельзя вызвать до объявления.
const greet = function (name) {
return `Hello ${name}`;
};
Стрелочные функции (Arrow function). Такая сокращённая запись функций подходит для небольшого блока кода, которому не нужен собственный контекст. Существенное отличие — это контекст. У стрелочных функций нет своего this. Он берётся из верхнего окружения. Грубо говоря, this — это ссылка на некий объект, к свойствам которого можно получить доступ внутри вызова функции. Этот this — и есть контекст выполнения.
const greet = (name) => {
return `Hello ${name}`;
};
Массивы. Методы работы с массивами
В JavaScript можно объявить массив несколькими способами:
const arr = new Array();
const arr = []; // чаще всего используется такой вариант — он проще и красивее.
Элементы массива могут принадлежать к разным типам данных. В JS есть специальные методы, которые изменяют массив:
- push — добавляет элемент в конец массива и возвращает новую длину массива,
- pop — удаляет последний элемент массива и возвращает его значение,
- shift — удаляет элемент из начала и сдвигает в начало остальную часть массива (второй элемент станет первым, третий — вторым и так далее),
- unshift — добавляет элемент в начало массива и возвращает новую длину массива.
Метод forEach. Классический метод для перебора массива:
const arr = [1, 2, 3];
arr.forEach((item, i, arr) => {
console.log(i, item, arr);
});
Метод filter. Возвращает новый массив из элементов, которые прошли проверку. При этом исходный массив остаётся прежним:
const arr = [1, 2, 3];
const comparator = number => number < 2;
const result = arr.filter(comparator); // [1]
Метод map. Метод для преобразования элементов массива. Создаёт новый массив на основе существующего.
const statuses = ['approved', 'rejected', 'waiting'];
statuses.map((status, index) => ({value: index, title: status}));
Методы reduce и reduceRight. Они сводят массив к какому-то одному значению: числу, массиву, объекту. Работают одинаково, только reduce перебирает элементы массива слева направо, а reduceRight — справа налево.
const arr = [1, 2, 3, 4, 5];
arr.reduce((result, item) => result + (item * item + 100), 0);
Объекты Объекты в JavaScript представляют собой хранилище более сложных сущностей. Данный инструмент является одной из основ языка.
const obj = {
propName: ‘Тест’
};
Объект может содержать другие объекты, массивы и иные типы данных. Метод Object.keys, который возвращает массив с ключами. Но ключи — не единственный способ обратиться к содержимому объекта. В некоторых случаях лучше подойдут методы values и entries:
- values возвращает значения свойств массива,
- entries возвращает и ключи, и значения.
Можно проверить наличие свойства у объекта:
message.hasOwnProperty('text'); // true
Прототипы В js есть возможность связывать объекты. Для этого есть специальное внутреннее поле Prototype. Объект, на который указывает ссылка в Prototype, называется прототипом. Из него текущий объект черпает недостающие методы и свойства. Свойство Prototype внутреннее и скрытое, но есть много способов задать его. Один из них — использовать proto.
const message = {
send(text) { }
};
const textMessage = {
formatter() {},
};
textMessage.__proto__ = message;
textMessage.send('text');
Классы В js подобие классов было задолго до ES6 c его привычным синтаксисом. Ранее объекты и классы создавались с помощью прототипов или с помощью функций.
function User(name) {
this.sayHi = function() {
console.log(`Hello, ${name}`);
};
}
В ES6 появилась известная конструкция class, работающая аналогично другим объектно-ориентированным языкам.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
Коллекции Map и Set Map – это коллекция ключ/значение, как и Object. Но основное отличие в том, что Map позволяет использовать ключи любого типа. Методы и свойства:
- new Map() – создаёт коллекцию.
- map.set(key, value) – записывает по ключу key значение value.
- map.get(key) – возвращает значение по ключу или undefined, если ключ key отсутствует.
- map.has(key) – возвращает true, если ключ key присутствует в коллекции, иначе false.
- map.delete(key) – удаляет элемент (пару «ключ/значение») по ключу key.
- map.clear() – очищает коллекцию от всех элементов.
- map.size – возвращает текущее количество элементов.
let map = new Map();
map.set("1", "str1"); // строка в качестве ключа
map.set(1, "num1"); // цифра как ключ
map.set(true, "bool1"); // булево значение как ключ
// помните, обычный объект Object приводит ключи к строкам?
// Map сохраняет тип ключей, так что в этом случае сохранится 2 разных значения:
alert(map.get(1)); // "num1"
alert(map.get("1")); // "str1"
alert(map.size); // 3
spread и деструктуризация Спред-синтаксис (spread) ... позволяет передавать итерируемые коллекции (например, массивы или строки) как список аргументов функции или добавлять содержащиеся в них элементы в новый массив.
Спред применятся и для объектов, чтобы копировать пары ключ-значение из одного объекта в другой.
const donor = ['это', 'старые', 'значения'];
const newArray = [...donor, 1, true, 'мама'];
const persona = { name: 'Иван', lastName: 'Объектов'}
const userData = { ...persona, username: 'killer3000' }
Деструктуризация — это синтаксис, позволяющий упростить присваивание переменным значений свойств объекта или элементов массива.
const person = {name: 'Александр', age: '37'}
const {name, age} = person
const planets = ['Меркурий', 'Венера', 'Земля', 'Марс']
const [first, second, third] = planets
Браузерные хранилища Web Storage – это интерфейс взаимодействия с хранилищем. Есть две реализации этого API: localStorage и sessionStorage.
localStorage – это объект, хранящийся в window, который позволяет долговременно сохранять данные в браузере. Работает как хранилище данных в формате ключ-значение — при сохранении данных мы указываем имя поля, в которое должны быть сохранены данные, и затем используем это имя для их получения.
Значения хранятся в виде строк. При попытке сохранения других типов данных, они будут приведены к строке.
localStorage.setItem('name', 'Дока Дог');
localStorage.getItem('name');
sessionStorage - это объект, хранящийся в window, который позволяет сохранять данные в браузере на время сессии. Этот тип хранилища очень похож на localStorage и работает как хранилище данных в формате ключ-значение.
sessionStorage.setItem('name', 'Собака Дока');
sessionStorage.getItem('name');
Работа с DOM Методы поиска элементов:
- getElementById — поиск элемента по идентификатору;
- getElementsByClassName — поиск элементов по названию класса;
- getElementsByTagName — поиск элементов по названию тега;
- querySelector — поиск первого элемента, подходящего под CSS-селектор;
- querySelectorAll — поиск всех элементов подходящих под CSS-селектор.
Методы работы с содержимым элемента:
- innerHTML - позволяет получить HTML-содержимое элемента в виде строки
- outerHTML - содержит HTML элемента целиком
- textContent - предоставляет доступ к тексту внутри элемента за вычетом всех тегов
- value – значение для , и
DOM-узел можно создать двумя методами:
- document.createElement(tag)
- document.createTextNode(text)
Методы вставки:
- node.append(...nodes or strings) – добавляет узлы или строки в конец node,
- node.prepend(...nodes or strings) – вставляет узлы или строки в начало node,
- node.before(...nodes or strings) –- вставляет узлы или строки до node,
- node.after(...nodes or strings) –- вставляет узлы или строки после node,
- node.replaceWith(...nodes or strings) –- заменяет node заданными узлами или строками.
- и др.
Обработка событий События — это сигналы, которые браузер посылает разработчику, а разработчик может на сигнал реагировать. События бывают разных типов: клик, нажатие клавиши на клавиатуре, прокрутка страницы и так далее. Происходящие события можно обрабатывать и выполнять код, когда нужное событие происходит.
Существует два способа обработать события:
- с помощью on-свойств DOM-элементов;
- методом addEventListener()
Каждый DOM-элемент имеет большой набор свойств, которые начинаются на on:
- onclick;
- onscroll;
- onkeypress;
- onmouseenter;
- и так далее.
const buttonElement = document.getElementById('change');
buttonElement.onclick = function() {
squareDiv.style = `background-color: #FFF;`
}
Если обрабатывать события с помощью on-свойств, то получится добавить только одну функцию-обработчик на каждый элемент. Часто одного обработчика недостаточно. Чтобы не создавать ограничение на пустом месте, используют альтернативный метод подписки на события — метод addEventListener().
Метод вызывается у DOM-элемента. Аргументами нужно передать тип события (справочная информация) и функцию, которую нужно выполнить.
const buttonElement = document.getElementById('change');
buttonElement.addEventListener('click', function() {
squareDiv.style = `background-color: #FFF};`
});
Важный аспект событийной модели — механизм распространения событий (event propagation). Он определяет, как события взаимодействуют с узлами DOM при достижении целевого элемента.
Возникая, событие проходит через все родительские элементы (capturing phase), достигает целевого элемента (target phase), и затем вновь поднимается по иерархии родительских элементов (bubbling phase).
Практическая часть
- Создайте Javascript файл и подключите его к странице.
- Реализуйте функцию, принимающую два числа и возвращающая наибольшее из этих двух чисел.
- Реализуйте функцию, которая принимает число и возвращает массив, содержащий числа от 0 до указанного числа.
- Реализуйте функцию, которая получает массив чисел произвольной длинны и возвращает новый массив, который содержит четные числа из переданного массива
- Сверстайте форму-анкету. Анкета должна состоять из следующих элементов:
Фамилия – поле ввода текста
Имя – поле ввода текста
Пол – выбор из двух вариантов
Номер телефона – поле ввода текста
email – поле ввода email
Должность - выбор из выпадающего списка, варианты придумать самостоятельно),
Трудовые обязанности – поле ввода многострочного текста
Кнопка Сохранить – сохранит введенные данные
Кнопка Сбросить – очистит поля формы
Все поля формы обязательны для заполнения, поэтому скрипт должен проверять поля на наличие введенных значений и соответствие этих значений типу поля сразу после ввода данных пользователем. В случае если поле пустое или данные не соответствуют типу, то под полем нужно вывести описание ошибки. Если пользователь ввел корректные данные, то после ввода ошибка должна пропасть, если отображалась ранее.
Поля с ошибкой должны стилистически выделяться. Например, рамкой красного цвета.
При нажатии кнопки Сохранить, скрипт должен пройтись по форме и собрать введенные данные в виде объекта, свойства которого будут соответствовать названиям полей формы и содержать значения из этой формы.
Если в форме имеются ошибки – скрипт должен вывести сообщение с предупреждением пользователю, что сохранение не удалось и нужно исправить ошибки формы.
Если в форме нет ошибок, то обработчик кнопки Сохранить помещает объект с данными в localStorage в поле formData. После записи данных нужно вывести сообщение, что данные успешно сохранены.
- Добавьте кнопку «Выгрузить данные». Обработчик данной кнопки должен достать информацию из localStorage и заполнить ею форму.