В уроке про условные конструкции был использован объект с данными пользователя Кодовёнка Хекслетовича:
const user = {
name: 'Кодовёнок',
surname: 'Хекслетович',
login: 'hexlet-code',
}
При обращении к полям объекта использовалась схема объект.ключ
. Таким способом были получены данные об имени, фамилии и логине пользователя:
-
const user = {
name: 'Кодовёнок',
surname: 'Хекслетович',
login: 'hexlet-code',
}
section.user-profile
p.name
if user.name && user.surname
| #{user.name} #{user.surname}
else
| #{user.login}
Преобразуем немного задачу и выведем пользователя в рейтинге обучающихся. Добавим количество баллов и все данные в таблицу:
-
const user = {
name: 'Кодовёнок',
surname: 'Хекслетович',
login: 'hexlet-code',
scores: 1271
}
section.container
h2 Рейтинг пользователей
table
thead
tr
th Имя
th Фамилия
th Логин
th Баллы
tbody
tr
td= user.name
td= user.surname
td= user.login
td= user.scores
Задача легко решается, если необходимо вывести одного пользователя. А что же делать, если пользователя 2? 3? 100? Есть два способа:
- Плохой: записать каждого пользователя в свою переменную и методом «копировать-вставить» добавить всех пользователей.
- Хороший: создать массив
users
, внутри которого будут все пользователи. Таким образом каждому пользователю будет выделено своё место в массиве, а значит можно удобно добавлять или удалять пользователей.
Создадим массив users
и добавим туда несколько разных пользователей:
const users = [
{
name: 'Кодовёнок',
surname: 'Хекслетович',
login: 'hexlet-code',
scores: 1271
},
{
name: 'Король',
surname: 'Вёрстки',
login: 'king-of-layout',
scores: 1100
},
]
Для обхода такого массива используются специальные конструкции — циклы. Их задача — пройтись по каждому элементу массива и получить информацию внутри него. Проход по элементам называется итерацией. Во время первой итерации будут получены данные Кодовёнка Хекслетовича. Во время второй итерации данные Короля Вёрстки.
Основным типом цикла в Pug считается цикл each in
. Буквально его можно читать как для каждого «a» внутри «b». Где:
- «a» — произвольное имя переменной, которая будет доступна во время итерации.
- «b» — массив или объект, из которого необходимо получить данные.
-
const users = [
{
name: 'Кодовёнок',
surname: 'Хекслетович',
login: 'hexlet-code',
scores: 1271
},
{
name: 'Король',
surname: 'Вёрстки',
login: 'king-of-layout',
scores: 1100
},
]
section.container
h2 Рейтинг пользователей
table
thead
tr
th Имя
th Фамилия
th Логин
th Баллы
tbody
each user in users
tr
td= user.name
td= user.surname
td= user.login
td= user.scores
<section class="container">
<h2>Рейтинг пользователей</h2>
<table>
<thead>
<tr>
<th>Имя</th>
<th>Фамилия</th>
<th>Логин</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr>
<td>Кодовёнок</td>
<td>Хекслетович</td>
<td>hexlet-code</td>
<td>1271</td>
</tr>
<tr>
<td>Король</td>
<td>Вёрстки</td>
<td>king-of-layout</td>
<td>1100</td>
</tr>
</tbody>
</table>
</section>
Главное изменение произошло добавлением всего одной строки: each user in users
. Запись читается следующим образом: для каждого user в массиве users и далее вывод табличной строки с данными.
Важно: вы можете присвоить любое имя переменной, которая будет доступна внутри цикла. В прошлом примере таким именем может быть не user
, а people
или как-то иначе. Только вы выбираете это имя, но старайтесь называть его так, чтобы было понятно, что кроется за этим названием. Если код внутри цикла большой, то именно от именования зависит то, как быстро и точно будет интерпретирован код вами или другим разработчиком.
Подробнее можно почитать в статьях:
- Совершенный код: именование в программировании
- Совершенный код: ошибки именования в программировании I
Нельзя точно быть уверенным, что массив, по которому будет происходить перебор имеет хоть один элемент. Если нет ни одного элемента, то всё, что внутри массива не будет выведено. В этот момент пользователю важно знать, что информации нет, а не возникла ошибка на странице. Для этого можно использовать конструкцию each else
. Это схоже с условной конструкцией, но срабатывает только при пустом массиве.
- const users = []
section.container
h2 Рейтинг пользователей
table
thead
tr
th Имя
th Фамилия
th Логин
th Баллы
tbody
each user in users
tr
td= user.name
td= user.surname
td= user.login
td= user.scores
else
tr
td(colspan='4') Нет пользователей
<section class="container">
<h2>Рейтинг пользователей</h2>
<table>
<thead>
<tr>
<th>Имя</th>
<th>Фамилия</th>
<th>Логин</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4">Нет пользователей</td>
</tr>
</tbody>
</table>
</section>
Код из прошлого примера эквивалентен следующей записи:
- const users = []
if users.length
each user in users
tr
td= user.name
td= user.surname
td= user.login
td= user.scores
else
tr
td(colspan='4') Нет пользователей
Вложенные циклы и получение ключа объекта
При переборе объекта бывает необходимо получить не только значение, но и ключ, по которому располагается объект. Например, пользователи могут делиться на разные группы: пользователи, модераторы, администраторы. В таком случае объект может иметь следующий вид:
const users = {
admin: [
{
name: 'Кодовёнок',
surname: 'Хекслетович',
},
],
moderator: [
{
name: 'Король',
surname: 'Вёрстки',
},
{
name: 'Алексей',
surname: 'Примадонин',
},
],
}
Объект users
имеет несколько ключей: admin
и moderator
, значением которых являются массивы пользователей. Для вывода такого списка вместе с указанием должности используется немного изменённый синтаксис цикла each
. В нём необходимо получить имя ключа и массив.
each people, position in users
h2= position
ul
each user in people
li= user.name + ' ' + user.surname
Из объекта users
принимаются несколько данных: в переменную people
попадает значение, а в переменную position
ключ. Обратите внимание на порядок переменных — вначале данные, а потом ключ.
В этом примере используется вложенный цикл. Такая практика является стандартным для обхода больших данных. При первой итерации в верхнем цикле вытаскиваются следующие данные:
const people = [
{
name: 'Кодовёнок',
surname: 'Хекслетович',
},
];
const position = 'admin';
В дальнейшем идет перебор по массиву people
, который происходит так же, как и в примере выше.
<h2>admin</h2>
<ul>
<li>Кодовёнок Хекслетович</li>
</ul>
<h2>moderator</h2>
<ul>
<li>Король Вёрстки</li>
<li>Алексей Примадонин</li>
</ul>
Цикл while
Цикл each
по праву считается основным при работе с Pug, но он не является единственным. Встречаются ситуации, когда необходимо несколько раз повторить одни и те же действия. В этом случае each
никак не поможет, но в Pug существует ещё один тип цикла — while
. Его задача — повторение участка кода пока истинно условие. Например,
- let count = 0;
ul
while count < 5
li= "Hello, my number is " + count
- count += 1;
<ul>
<li>Hello, my number is 0</li>
<li>Hello, my number is 1</li>
<li>Hello, my number is 2</li>
<li>Hello, my number is 3</li>
<li>Hello, my number is 4</li>
</ul>
При использовании цикла while
важно следить за тем, чтобы условие рано или поздно преобразовалось в ложь. Это частая ошибка, которая может привести к бесконечному циклу. В прошлом примере для получения бесконечного цикла достаточно опустить строку count += 1;
. Без неё значение переменной count
всегда будет равно нулю, а значит условие count < 5
будет истинным в любой момент времени компиляции.
Дополнительное задание
В файл icon.pug попадает массив следующего вида:
-
const icons = {
free: [
{
name: 'robot',
url: './icons/robot.svg'
},
{
name: 'hexlet',
url: './icons/hexlet.svg'
}
],
premium: [
{
name: 'cat',
url: './icons/premium/cat.svg'
},
{
name: 'dog',
url: './icons/premium/dog.svg'
}
]
};
Преобразуйте данные в шаблон следующего вида:
<h2>free</h2>
<ul>
<li><a href="./icons/robot.svg">robot</a></li>
<li><a href="./icons/hexlet.svg">hexlet</a></li>
</ul>
<h2>premium</h2>
<ul>
<li><a href="./icons/premium/cat.svg">cat</a></li>
<li><a href="./icons/premium/dog.svg">dog</a></li>
</ul>
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.