Фундамент Ф1 · урок 5 з 12
Масиви та їхні методи
Масив — впорядкований список значень. Майже всі дані в застосунку — масиви обʼєктів: задачі,
користувачі, рядки таблиці, пункти меню. А методи масивів — map, filter, find —
найчастіший код в Angular: @for у шаблоні, computed зі списком, обробка відповіді
сервера. Це найважливіший урок модуля, не поспішай.
Основи: індекс і довжина
const tasks = ['Звіт', 'Дизайн', 'Реліз'];
tasks[0]; // 'Звіт' — нумерація з нуля!
tasks[2]; // 'Реліз'
tasks[3]; // undefined — такого елемента немає
tasks.length; // 3
tasks[tasks.length - 1]; // 'Реліз' — останній
tasks.at(-1); // те саме, коротше
tasks.includes('Дизайн'); // true — чи є такий елемент
Індекси починаються з нуля, тому останній елемент — length - 1. Звернення за межі масиву не дає
помилки, а мовчки повертає undefined.
Змінити масив: два світи
Одні методи змінюють сам масив — кажуть, «мутують». Інші повертають новий, не чіпаючи старого. Цю різницю треба знати напамʼять: в Angular мутація — джерело багів «дані змінились, а екран ні». Чому так — урок 6.
| Мутують ⚠️ | Повертають новий ✓ |
|---|---|
push(x) — додати в кінець | [...list, x] — новий масив з x у кінці |
unshift(x) — додати на початок | [x, ...list] |
pop(), shift() — забрати з кінця чи початку | list.slice(0, -1), list.slice(1) |
splice(i, n) — вирізати | list.filter(…) — лишити все, крім… |
sort(), reverse() | toSorted(), toReversed() |
Три крапки ...list — це spread: «розклади тут усі елементи списку». Детально — в уроці 6.
Перебір
for (const task of tasks) {
console.log(task);
}
tasks.forEach((task, index) => {
console.log(index, task); // колбек отримує елемент і його номер
});
forEach — це метод, який викликає твій колбек для кожного елемента. Нічого не повертає: він для дій,
а не для обчислень. Для обчислень є трійка нижче.
map, filter, find: трійка, без якої ніяк
Візьмемо реалістичні дані — масив обʼєктів:
const tasks = [
{ id: 1, title: 'Звіт', done: false, hours: 3 },
{ id: 2, title: 'Дизайн', done: true, hours: 5 },
{ id: 3, title: 'Реліз', done: false, hours: 8 },
];
filter — відібрати. Викликає колбек для кожного елемента й лишає ті, для яких він повернув
truthy. Елементів може стати менше.
tasks.filter(t => !t.done); // дві задачі: Звіт і Реліз
map — перетворити. Повертає новий масив тієї самої довжини, де кожен елемент — результат
колбека.
tasks.map(t => t.title); // ['Звіт', 'Дизайн', 'Реліз']
find — знайти перший, що підходить. Повертає сам елемент, а не масив, або
undefined, якщо нічого не знайшов.
tasks.find(t => t.id === 2); // { id: 2, title: 'Дизайн', … }
tasks.find(t => t.id === 99); // undefined
Їх зручно зʼєднувати в ланцюжок: кожен крок отримує результат попереднього.
Поекспериментуй: відбери лише виконані задачі, виведи години кожної, знайди задачу з
id: 3.
Ще кілька корисних
some(fn)— чи є хоч один такий?tasks.some(t => t.done)→true.every(fn)— чи всі такі?tasks.every(t => t.done)→false.findIndex(fn)— номер першого такого або-1.join(', ')— склеїти в рядок:['a', 'b'].join(', ')→'a, b'.- У рядків теж є методи:
'звіт'.toUpperCase()→'ЗВІТ',' так '.trim()→'так','Звіт'.includes('ві')→true.
Виведи масив назв невиконаних задач, на які треба більше 2 годин, — великими
літерами. Одним console.log.
tasks.filter(t => !t.done && t.hours > 2).map(t => t.title.toUpperCase())reduce: згорнути в одне значення
reduce проходить масив і накопичує результат: суму, максимум, обʼєкт-групування.
const totalHours = tasks.reduce((sum, t) => sum + t.hours, 0); // 16
// ↑ накопичене ↑ поточний ↑ з чого почати
Читай так: «почни з нуля; для кожної задачі додай її години до суми». Якщо reduce поки здається
заплутаним — нічого страшного: у більшості випадків вистачає map, filter і звичайного
циклу.
Порахуй, скільки годин лишилось на невиконані задачі.
filter, потім reduce((sum, t) => sum + t.hours, 0).sort: дві пастки
[10, 9, 1].sort(); // [1, 10, 9] — сортує як рядки!
[10, 9, 1].sort((a, b) => a - b); // [1, 9, 10] — числа порівнюють функцією
names.sort((a, b) => a.localeCompare(b, 'uk')); // рядки — з урахуванням абетки
Перша пастка: без функції-порівняння sort перетворює все на рядки й порівнює посимвольно. Друга:
sort мутує масив. Щоб не чіпати оригінал — [...list].sort(…) або новіший
list.toSorted(…).
Вгадай кожен рядок, потім запусти. Особливо цікаві імена: подивись, куди потрапить «Єва»
без localeCompare.
list[list.length]— це вже за межами: останній —list.length - 1.tasks.map(t => { t.title })— фігурні дужки безreturn, вийде масив зundefined.- Від
findчекають масив, а він повертає один елемент абоundefined. sort()без функції для чисел — і10опиняється перед9.- Результат
forEachкладуть у змінну — а тамundefined. Для нового масиву єmap.
Підсумок
- Індекси з нуля, останній —
length - 1абоat(-1). push,splice,sortмутують. Spread,filter,map,sliceповертають новий масив.filter— відібрати,map— перетворити,find— знайти один. Зʼєднуються в ланцюжок.reduceзгортає масив в одне значення.sortдля чисел потребує(a, b) => a - b.