diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index c4d9698f4..0ecb80c41 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -7,8 +7,8 @@ Ми вже знаємо методи, які додають чи видаляють елементи з початку чи з кінця: - `arr.push(...items)` -- додає елементи до кінця, -- `arr.pop()` -- дістає елемент з кінця, -- `arr.shift()` -- дістає елемент з початку, +- `arr.pop()` -- видаляє елемент з кінця, +- `arr.shift()` -- видаляє елемент з початку, - `arr.unshift(...items)` -- додає елементи в початок. Розглянемо й інші. @@ -32,7 +32,7 @@ alert( arr.length ); // 3 Начебто, елемент був видалений, але при перевірці виявляється, що масив все ще має 3 елементи `arr.length == 3`. -Це нормально, тому що все, що робить `delete obj.key` -- це видаляє значення за ключем `key`. Це нормально для обʼєктів, але для масивів ми звичайно хочемо, щоб інші елементи змістились і зайняли місце, що звільнилося. Ми чекаємо, що масив стане коротшим. +Це нормально, тому що все, що робить `delete obj.key` -- це видаляє значення за ключем `key`. Це нормально для обʼєктів, але для масивів ми звичайно ж хочемо, щоб інші елементи змістились і зайняли місце, яке звільнилося. Ми очікуємо, що масив стане коротшим. Тому слід застосовувати спеціальні методи. @@ -44,7 +44,7 @@ alert( arr.length ); // 3 arr.splice(start[, deleteCount, elem1, ..., elemN]) ``` -Він змінює `arr` починаючи з позиції `start`: видаляє `deleteCount` елементів і вставляє `elem1, ..., elemN` на їх місце. Повертається масив з видалених елементів. +Він змінює `arr` починаючи з позиції `start`: видаляє `deleteCount` елементів і вставляє `elem1, ..., elemN` на їх місце. І повертає масив з видалених елементів. Цей метод легко зрозуміти на прикладах. @@ -89,16 +89,16 @@ alert( removed ); // "I", "study" <-- масив видалених елемен ```js run let arr = ["I", "study", "JavaScript"]; -// починаючт з індекса 2 +// починаючи з індекса 2 // видалимо 0 елементів -// ваставити "complex" та "language" +// вставимо "complex" та "language" arr.splice(2, 0, "complex", "language"); alert( arr ); // "I", "study", "complex", "language", "JavaScript" ``` ````smart header="Дозволяються відʼємні індекси" -Тут і в інших методах масиву допускаються відʼємні індекси. Вони дозволяють почати відлік елементів з кінця, як тут: +Тут, як і в інших методах масиву допускаються відʼємні індекси. Вони дозволяють почати відлік елементів з кінця. Наприклад: ```js run let arr = [1, 2, 5]; @@ -257,7 +257,7 @@ alert( arr.includes(1) ); // true Якщо ми хочемо перевірити наявність `item` в массиві, і нема потреби знати його точний індекс, тоді краще використати `arr.includes`. -Метод [arr.lastIndexOf](mdn:js/Array/lastIndexOf) такий самий, як `indexOf`, але шукає справа наліво. +Метод [arr.lastIndexOf](mdn:js/Array/lastIndexOf) такий самий, як `indexOf`, але шукає з права наліво. ```js run let fruits = ['Apple', 'Orange', 'Apple'] @@ -274,19 +274,19 @@ const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (повинен бути 0, але === перевірка на рівність не працює з NaN) alert( arr.includes(NaN) );// true (вірно) ``` -That's because `includes` was added to JavaScript much later and uses the more up to date comparison algorithm internally. +Це тому, що `includes` було додано до JavaScript набагато пізніше і він використовує набагато актуальніші алгоритми. ```` ### find і findIndex/findLastIndex -Уявіть, що у нас є масив обʼєктів. Як нам знайти обʼєкт за певною умовою? +Уявіть, що у нас є масив обʼєктів. Як нам знайти обʼєкт, який відповідає певній умові? Тут стане в нагоді метод [arr.find(fn)](mdn:js/Array/find). Його синтаксис такий: ```js let result = arr.find(function(item, index, array) { - // якщо true - повертається поточний елемент і перебір закінчується + // якщо функція поверне true - повертається поточний елемент і перебір закінчується // якщо всі ітерації виявилися помилковими, повертається undefined }); ``` @@ -294,10 +294,10 @@ let result = arr.find(function(item, index, array) { Функція викликається по черзі для кожного елемента масиву: - `item` -- черговий елемент масиву. -- `index` -- його індекс. +- `index` -- індекс цього елемента. - `array` -- сам масив. -Якщо функція повертає `true`, пошук припиняється, повертається `item`. Якщо нічого не знайдено, повертається `undefined`. +Якщо функція повертає `true`, пошук припиняється і повертається `item`. Якщо ж функція-колбек ні при якому з елементів не повернула true, тобто якщо об'єкта, який би відповідав нашій умові не знайдено, то метод `.find` повертає `undefined`. Наприклад, у нас є масив користувачів, кожен з яких має поля `id` та `name`. Давайте знайдемо той де `id == 1`: @@ -313,11 +313,11 @@ let user = users.find(item => item.id == 1); alert(user.name); // John ``` -У реальному житті масиви обʼєктів -- звичайна справа, тому метод `find` вкрай корисний. +У реальному житті масиви обʼєктів використовуються дуже часто, тому метод `find` вкрай корисний. -Зверніть увагу, що в даному прикладі ми передаємо `find` функцію `item => item.id == 1`, з одним аргументом. Це типово, інші аргументи цієї функції використовуються рідко. +Зверніть увагу, що в даному прикладі ми передаємо в `find` функцію `item => item.id == 1`, з одним аргументом. Це досить поширене явище. Інші аргументи цієї функції використовуються рідко. -Метод [arr.findIndex](mdn:js/Array/findIndex) -- по суті, те ж саме, але повертає індекс, на якому був знайдений елемент, а не сам елемент, і `-1`, якщо нічого не знайдено. +Метод [arr.findIndex](mdn:js/Array/findIndex) -- працює по суті так само. Але повертає не сам елемент, а індекс, на якому був знайдений елемент. А якщо нічого не знайдено, то повертає `-1`. Метод [arr.findLastIndex](mdn:js/Array/findLastIndex) схожий на `findIndex`, але шукає справа наліво, подібно до `lastIndexOf`. @@ -340,16 +340,16 @@ alert(users.findLastIndex(user => user.name == 'John')); // 3 ### filter -Метод `find` шукає один (перший) елемент, на якому функція-колбек поверне `true`. +Метод `find` повертає лише один елемент, на якому функція-колбек поверне `true`. На той випадок, якщо знайдених елементів може бути багато, передбачений метод [arr.filter(fn)](mdn:js/Array/filter). -Синтаксис цього методу схожий з `find`, але `filter` повертає масив з усіх відфільтрованих елементів: +Синтаксис цього методу схожий з `find`, але `filter` повертає масив з усіма елементами, які відповідають умові: ```js let results = arr.filter(function(item, index, array) { - // якщо true - елемент додається до результату, і перебір триває - // повертається порожній масив в разі, якщо нічого не знайдено + // якщо true - елемент додається до масиву з результатом, і перебір продовжується. По закінченню повертається масив з результатами. + // якщо ні один з елементів не відповідає умові, то повертається порожній масив. }); ``` @@ -418,7 +418,7 @@ alert( arr ); // *!*1, 15, 2*/!* Буквально, елементи перетворюються в рядки при порівнянні. Для рядків застосовується лексикографічний порядок, і дійсно виходить, що `"2"> "15"`. -Щоб використовувати наш власний порядок сортування, нам потрібно надати функцію як аргумент `arr.sort()`. +Щоб використовувати наш власний порядок сортування, нам потрібно надати функцію аргументом в `arr.sort()`. Функція має порівняти два довільних значення та повернути: @@ -450,9 +450,9 @@ alert(arr); // *!*1, 2, 15*/!* Тепер все працює як треба. -Візьмімо паузу і подумаємо, що ж відбувається. Згаданий раніше масив `arr` може бути масивом чого завгодно, вірно? Він може містити числа, рядки, обʼєкти або щось ще. У нас є набір якихось елементів. Щоб впорядкувати його, нам потрібна функція, яка визначає порядок, яка знає, як порівнювати його елементи. За замовчуванням елементи сортуються як рядки. +Давайте відволічемось і подумаємо, що ж відбувається. Згаданий раніше масив `arr` може бути масивом з чим-завгодно, вірно? Він може містити числа, рядки, обʼєкти або щось ще. У нас є набір якихось елементів. Щоб впорядкувати його, нам потрібна функція, яка визначає порядок, яка знає, як порівнювати його елементи. За замовчуванням елементи сортуються як рядки. -Метод `arr.sort(fn)` реалізує загальний алгоритм сортування. Нам не потрібно піклуватися про те, як він працює всередині (в більшості випадків це оптимізоване [швидке сортування](https://en.wikipedia.org/wiki/Quicksort) чи [Timsort](https://en.wikipedia.org/wiki/Timsort)). Реалізується прохід по масиву, порівнюються його елементи за допомогою наданої функції і змінюється їх порядок. Все, що залишається нам, це надати `fn`, яка робить це порівняння. +Метод `arr.sort(fn)` реалізує загальний алгоритм сортування. Нам не потрібно піклуватися про те, як він працює всередині (в більшості випадків це оптимізоване [швидке сортування](https://en.wikipedia.org/wiki/Quicksort) чи [Timsort](https://en.wikipedia.org/wiki/Timsort)). Реалізується прохід по масиву, порівнюються його елементи за допомогою наданої функції і змінюється їх порядок. Все, що треба від нас - це надати `fn`, яка робить це порівняння. До речі, якщо ми коли-небудь захочемо дізнатися, які елементи порівнюються -- ніщо не заважає нам вивести їх на екран: @@ -490,9 +490,9 @@ arr.sort( (a, b) => a - b ); ```` ````smart header="Використовуйте `localeCompare` для рядків" -Памʼятаєте алгоритм порівняння [рядків](info:string#correct-comparisons)? Він порівнює літери за їх кодами за замовчуванням. +Памʼятаєте алгоритм порівняння [рядків](info:string#correct-comparisons)? За замовчуванням він порівнює літери за їх кодами. -Для багатьох алфавітів краще використовувати метод `str.localeCompare` для правильного сортування літер, як наприклад `Ö`. +Для багатьох алфавітів краще використовувати метод `str.localeCompare` для правильного сортування літер, таких як `Ö`. Наприклад, давайте відсортуємо кілька країн німецькою мовою: @@ -522,28 +522,28 @@ alert( arr ); // 5,4,3,2,1 ### split та join -Ситуація з реального життя. Ми пишемо додаток для обміну повідомленнями, і відвідувач вводить імена тих, кому його відправити, через кому: Вася, Петя, Маша. Але нам-то набагато зручніше працювати з масивом імен, ніж з одним рядком. Як його отримати? +Ситуація з реального життя. Ми пишемо додаток для обміну повідомленнями, і відвідувач вводить імена тих, кому його відправити, через кому: Васько, Ярик, Марійка. Але нам то набагато зручніше працювати з масивом імен, ніж з одним рядком. Як отримати масив? -Метод [str.split(delim)](mdn:js/String/split) саме це і робить. Він розбиває рядок на масив по заданому роздільнику `delim`. +Метод [str.split(delim)](mdn:js/String/split) саме це і робить. Він розбиває рядок на масив по заданому роздільнику `delim` (з англ. deliminator - роздільник). У прикладі нижче таким роздільником є ​​рядок з коми та пропуску. ```js run -let names = 'Вася, Петя, Маша'; +let names = 'Васько, Ярик, Марійка'; let arr = names.split(', '); for (let name of arr) { - alert( `A message to ${name}.` ); // Повідомлення отримають: Вася (і інші імена) + alert( `A message to ${name}.` ); // Повідомлення отримають: Васько (і інші імена) } ``` У методу split є необовʼязковий другий числовий аргумент -- обмеження на кількість елементів в масиві. Якщо їх більше, ніж вказано, то залишок масиву буде відкинутий. На практиці це рідко використовується: ```js run -let arr = 'Вася, Петя, Маша, Іван'.split(', ', 2); +let arr = 'Васько, Ярик, Марійка, Івасик'.split(', ', 2); -alert(arr); // Вася, Петя +alert(arr); // Васько, Ярик ``` ````smart header="Розбивка на букви" @@ -556,16 +556,16 @@ alert( str.split('') ); // t,e,s,t ``` ```` -Виклик [arr.join(glue)](mdn:js/Array/join) робить в точності протилежне split. Він створює рядок з елементів `arr`, вставляючи `glue` між ними. +Виклик [arr.join(glue)](mdn:js/Array/join) робить в точності протилежне split. Він створює рядок з елементів `arr`, вставляючи `glue` між ними (з англ. glue - клей). Наприклад: ```js run -let arr = ["Вася", "Петя", "Маша"]; +let arr = ["Васько", "Ярик", "Марійка"]; let str = arr.join(';'); // обʼєднуємо масив в рядок за допомогою ";" -alert( str ); // Вася;Петя;Маша +alert( str ); // Васько;Ярик;Марійка ``` ### reduce/reduceRight @@ -588,14 +588,14 @@ let value = arr.reduce(function(accumulator, item, index, array) { Аргументи: -- `accumulator` -- результат попереднього виклику цієї функції, дорівнює `initial` при першому виклику (якщо переданий `initial`), +- `accumulator` -- (з англ. накопичувач) результат попереднього виклику цієї функції. При першому виклику дорівнює `initial`(якщо `initial` переданий), - `item` -- черговий елемент масиву, -- `index` -- його індекс, +- `index` -- індекс чергового елемента, - `array` -- сам масив. -При виконанні функції результат її виклику на попередньому елементі масиву передається як перший аргумент. +При виконанні функції результат її попереднього виклику передається на наступний виклик в якості першого аргумента. -Зрозуміти простіше, якщо думати про перший аргумент як «збирач» результатів попередніх викликів функції. Після закінчення він стає результатом `reduce`. +Зрозуміти простіше, якщо думати про перший аргумент як про «накопичував» результатів попередніх викликів функції. Після закінчення він стає результатом `reduce`. Звучить складно? @@ -615,9 +615,9 @@ alert(result); // 15 Давайте детальніше розберемо, як він працює. -1. При першому запуску `sum` дорівнює `initial` (останній аргумент `reduce`), тобто `0`, а `current` -- перший елемент масиву, рівний `1`. Таким чином, результат функції дорівнює `1`. -2. При другому запуску `sum = 1`, і до нього ми додаємо другий елемент масиву (`2`). -3. При третьому запуску `sum = 3`, до якого ми додаємо наступний елемент, і так далі... +1. При першому запуску `sum` дорівнює `initial` (останній аргумент `reduce`), тобто `0`. А `current` -- перший елемент масиву, рівний `1`. Таким чином, після першого запуску значення `sum` стає `1`. +2. При другому запуску накопичувач `sum` уже дорівнює `1`, і до нього ми додаємо другий елемент масиву (`2`). Таким чином, після другого запуску значення `sum` стає `2`. +3. При третьому запуску `sum` дорівнює `3`. І до нього ми додаємо наступний елемент, і так далі... Потік обчислень виходить такий: @@ -635,7 +635,7 @@ alert(result); // 15 Тут чітко видно, як результат попереднього виклику передається в перший аргумент наступного. -Ми також можемо опустити початкове значення: +Ми також можемо не задавати початкове (англ. initial) значення: ```js run let arr = [1, 2, 3, 4, 5]; @@ -648,9 +648,9 @@ alert( result ); // 15 Результат той самий. Це тому, що при відсутності `initial` в якості першого значення береться перший елемент масиву, а перебір стартує з другого. -Таблиця розрахунків така ж, як і вище, без першого рядка. +Таблиця розрахунків така ж, як і вище, просто без першого рядка. -Але таке використання вимагає крайньої обережності. Якщо масив порожній, то виклик `reduce` без початкового значення видасть помилку. +Але таке використання вимагає неймовірної обережності. Якщо масив порожній, то виклик `reduce` без початкового значення видасть помилку. Ось приклад: @@ -658,7 +658,7 @@ alert( result ); // 15 let arr = []; // Error: Reduce of empty array with no initial value -// якби існувало початкове значення, reduce повернув би його для порожнього масиву. +// якби існувало початкове значення, reduce повернув би його при порожньому масиві. arr.reduce((sum, current) => sum + current); ``` @@ -677,7 +677,7 @@ alert(typeof {}); // обʼєкт alert(typeof []); // також обʼєкт ``` -...Але масиви використовуються настільки часто, що для цього придумали спеціальний метод: [Array.isArray(value)](mdn:js/Array/isArray). Він повертає `true`, якщо `value` -- це масив, інакше `false`. +...Але масиви використовуються настільки часто, що для цього придумали спеціальний метод: [Array.isArray(value)](mdn:js/Array/isArray). Він повертає `true`, якщо `value` -- це масив, і `false` якщо ні. ```js run alert(Array.isArray({})); // false @@ -707,37 +707,37 @@ arr.map(func, thisArg); ```js run let army = { - minAge: 18, - maxAge: 27, - canJoin(user) { - return user.age >= this.minAge && user.age < this.maxAge; + minAge: 25, + maxAge: 60, + canBeBussified(user) { + return user.age >= this.minAge && user.age <= this.maxAge; } }; let users = [ - {age: 16}, - {age: 20}, - {age: 23}, - {age: 30} + {age: 19}, + {age: 26}, + {age: 33}, + {age: 61} ]; *!* -// знайти користувачів, для яких army.canJoin повертає true -let soldiers = users.filter(army.canJoin, army); +// знайти користувачів, яких можна бусифікувати (для яких army.canBeBussified повертає true) +let soldiers = users.filter(army.canBeBussified, army); */!* alert(soldiers.length); // 2 -alert(soldiers[0].age); // 20 -alert(soldiers[1].age); // 23 +alert(soldiers[0].age); // 26 +alert(soldiers[1].age); // 33 ``` -Якби ми в прикладі вище використовували просто `users.filter(army.canJoin)`, то виклик `army.canJoin` був би в режимі окремої функції, з `this=undefined`. Це призвело б до помилки. +Якби ми в прикладі вище використовували просто `users.filter(army.canBeBussified)`, то виклик `army.canBeBussified` був би в режимі окремої функції, з `this=undefined`. Це призвело б до помилки. -Виклик `users.filter(army.canJoin, army)` можна замінити на `users.filter(user => army.canJoin(user))`, який робить те ж саме. Останній запис використовується навіть частіше, оскільки стрілочна функція більш наочна. +Виклик `users.filter(army.canBeBussified, army)` можна замінити на `users.filter(user => army.canBeBussified(user))`, який робить те ж саме. Останній запис використовується навіть частіше, оскільки стрілочна функція більш наочна. ## Підсумки -Шпаргалка по методам масиву: +Шпаргалка з методів масиву: - Для додавання/видалення елементів: - `push(... items)` -- додає елементи до кінця, @@ -750,9 +750,9 @@ alert(soldiers[1].age); // 23 - Для пошуку серед елементів: - `indexOf/lastIndexOf(item, pos)` -- шукає `item`, починаючи з позиції `pos`, і повертає його індекс або `-1`, якщо нічого не знайдено. - - `includes(value)` -- повертає `true`, якщо в масиві є елемент `value`, в іншому випадку `false`. - - `find/filter(func)` -- фільтрує елементи через функцію і віддається перше/всі значення, при проходженні яких функція повертає `true`. - - `findIndex` схожий на `find`, але повертає індекс замість значення. + - `includes(value)` -- повертає `true`, якщо в масиві знайдено елемент `value`, або `false` якщо не знайдено. + - `find/filter(func)` -- фільтрують елементи через функцію і повертають перший/всі елементи, при використинні яких функція повертає `true`. І `undefined`/`[]` якщо таких елементів не знайдено. + - `findIndex` схожий на `find`, але повертає індекс замість значення. Або `-1` якщо не знайшов. - Для перебору елементів: - `forEach(func)` -- викликає `func` для кожного елемента. Нічого не повертає. @@ -761,11 +761,11 @@ alert(soldiers[1].age); // 23 - `map(func)` -- створює новий масив з результатів виклику `func` для кожного елемента. - `sort(func)` -- сортує масив «на місці», а потім повертає його. - `reverse()` -- «на місці» змінює порядок елементів на протилежний і повертає змінений масив. - - `split/join` -- перетворює рядок в масив і назад. - - `reduce(func, initial)` -- обчислює одне значення на основі всього масиву, викликаючи `func` для кожного елемента і передаючи проміжний результат між викликами. + - `split/join` -- перетворюють рядок в масив і назад. + - `reduce(func, initial)` -- обчислює накопичуване значення на основі всього масиву, викликаючи `func` для кожного елемента і передаючи проміжний результат між викликами. - Додатково: - - `Array.isArray(value)` перевіряє, чи є `value` масивом, якщо так, повертає `true`, інакше `false`. + - `Array.isArray(value)` перевіряє, чи є `value` масивом, якщо так, повертає `true`, і `false` якщо ні. Зверніть увагу, що методи `sort`, `reverse` та `splice` змінюють поточний масив. @@ -773,7 +773,7 @@ alert(soldiers[1].age); // 23 - [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) перевіряють масив. -Функція `fn` викликається для кожного елемента масиву, подібного до `map`. Якщо будь-які/усі результати є `true`, повертає `true`, інакше `false`. +Функція `fn` викликається для кожного елемента масиву, подібно до `map`. Якщо будь-які/усі результати є `true`, повертає `true`, інакше `false`. Ці методи поводяться приблизно як оператори `||` та `&&`. Якщо `fn` повертає істинне значення, `arr.some()` негайно повертає `true` і припиняє ітерацію по решті елементів. Якщо `fn` повертає хибне значення, `arr.every()` негайно повертає `false` і припиняє ітерацію по решті елементів. @@ -789,7 +789,7 @@ alert(soldiers[1].age); // 23 - [arr.fill(value, start, end)](mdn:js/Array/fill) -- заповнює масив повторюваними `value`, починаючи з індексу `start` до `end`. -- [arr.copyWithin(target, start, end)](mdn:js/Array/copyWithin) -- копіює свої елементи, починаючи з `start` і закінчуючи `end`, в власну позицію `target` (перезаписує існуючі). +- [arr.copyWithin(target, start, end)](mdn:js/Array/copyWithin) -- копіює свої елементи, починаючи з `start` і закінчуючи `end`, в власну позицію `target` (перезаписучи існуючі). - [arr.flat(depth)](mdn:js/Array/flat)/[arr.flatMap(fn)](mdn:js/Array/flatMap) -- створює новий, плоский масив з багатовимірного масиву. @@ -797,6 +797,6 @@ alert(soldiers[1].age); // 23 На перший погляд, може здатися, що існує дуже багато різних методів, які досить складно запамʼятати. Але це тільки так здається. -Уважно вивчіть шпаргалку, представлену вище, а потім, щоб попрактикуватися, вирішите завдання, запропоновані в цьому розділі. Так ви отримаєте необхідний досвід в правильному використанні методів масиву. +Уважно вивчіть шпаргалку, представлену вище, а потім, щоб попрактикуватися, повирішуйте завдання, запропоновані в цьому розділі. Так ви отримаєте необхідний досвід в правильному використанні методів масиву. -Кожного разу, коли вам буде необхідно щось зробити з масивом, а ви не знаєте, як це зробити -- приходьте сюди, дивіться на таблицю і шукайте правильний метод. Приклади допоможуть вам все зробити правильно, і незабаром ви швидко запамʼятайте методи без особливих зусиль. +Кожного разу, коли вам буде необхідно щось зробити з масивом, а ви не знаєте як це зробити -- приходьте сюди, дивіться на таблицю і шукайте правильний метод. Приклади допоможуть вам все зробити правильно, і незабаром ви швидко запамʼятайте методи без надмірних зусиль.