Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
iterables
  • Loading branch information
MykolaSopiha committed Sep 4, 2021
commit fb1a96f5a59085f756c7a59a2fbc32e9bf4aee88
38 changes: 19 additions & 19 deletions 1-js/05-data-types/06-iterable/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

*Ітеративні* об’єкти є узагальненням масивів. Це концепція, яка дозволяє нам зробити будь-який об’єкт придатним для використання в циклі `for..of`.

Звичайно, по масивам можна ітеруватися. Але є багато інших вбудованих об’єктів, які також можна ітерувати. Наприклад, рядки також можна ітерувати.
Звичайно, по масивах можна ітеруватися. Але є багато інших вбудованих об’єктів, які також можна ітерувати. Наприклад, рядки також можна ітерувати.

Якщо об’єкт технічно не є масивом, а представляє колекцію (list, set) чогось, то `for..of` - чудовий синтаксис для його обходу, тому давайте подивимося, як змусити його працювати.
Якщо об’єкт технічно не є масивом, а представляє колекцію (list, set) чогось, то `for..of` -- чудовий синтаксис для його обходу, тому подивімось, як змусити його працювати.


## Symbol.iterator

Ми можемо легко зрозуміти концепцію ітеративних об’єктіва, зробивши її власноруч.
Ми можемо легко зрозуміти концепцію ітеративних об’єктів, зробивши її власноруч.

Наприклад, у нас є об’єкт, який не є масивом, але виглядає придатним для `for..of`.

Expand Down Expand Up @@ -75,7 +75,7 @@ for (let num of range) {

Отже, об’єкт, що ітерує відокремлений від об’єкта, який він ітерує.

Технічно, ми можемо об’єднати їх і використовувати `range` в якості ітератора, щоб зробити код більш простим.
Технічно, ми можемо об’єднати їх і використовувати `range` в якості ітератора, щоб зробити код простішим.

Подібно до цього:

Expand Down Expand Up @@ -103,15 +103,15 @@ for (let num of range) {
}
```

Тепер `range[Symbol.iterator]()` повертає сам об'єкт `range`: він має необхідний `next()` метод і пам'ятає поточну ітерацію прогресу в `this.current`. Коротше? Так. А іноді це також добре.
Тепер `range[Symbol.iterator]()` повертає сам об’єкт `range`: він має необхідний `next()` метод і пам’ятає поточну ітерацію прогресу в `this.current`. Коротше? Так. А іноді це також добре.

Недоліком є те, що тепер неможливо мати два `for..of` цикли паралельно для проходження через об’єкт: вони будуть ділити ітераційний стан, тому що є тільки один ітератор -- сам об'єкт. Але два параллельних for-of це рідкісний випадок, навіть у асинхронізованих сценаріях.
Недоліком є те, що тепер неможливо мати два `for..of` цикли паралельно для проходження через об’єкт: вони будуть ділити ітераційний стан, тому що є тільки один ітератор -- сам об’єкт. Але два паралельних for-of це рідкісний випадок, навіть у асинхронізованих сценаріях.

```smart header="Infinite iterators"
Також можливі нескінченні ітератори. Наприклад, `range` стає нескінченним для `range.to = Infinity`. Або ми можемо зробити ітерований об'єкт, який генерує нескінченну послідовність псевдорандомних чисел. Це також може бути корисним.
Також можливі нескінченні ітератори. Наприклад, `range` стає нескінченним для `range.to = Infinity`. Або ми можемо зробити ітерований об’єкт, який генерує нескінченну послідовність псевдорандомних чисел. Це також може бути корисним.
Немає обмежень на `next`, він може повертати все більше і більше значень, це нормально.

Звичайно, `for..of` цикли через такий об’єкт буде безкінечним. Але ми завжди можемо зупинити його за допомогою `break`.
Звичайно, `for..of` цикли через такий об’єкт буде нескінченним. Але ми завжди можемо зупинити його за допомогою `break`.
```


Expand Down Expand Up @@ -139,7 +139,7 @@ for (let char of str) {

## Виклик ітератора явно

Для більш глибокого розуміння, давайте подивимося, як явно використовувати ітератор.
Для глибшого розуміння, подивімось, як явно використовувати ітератор.

Ми будемо ітерувати рядок точно так само, як для `for..of`, але з прямими викликами. Цей код створює ітератор рядка і отримує значення від нього "вручну":

Expand All @@ -166,17 +166,17 @@ while (true) {

Ці два офіційних терміни виглядають подібними, але дуже різні. Будь ласка, переконайтеся, що ви добре розумієте їх, щоб уникнути плутанини.

- *Ітеровані* -- це об'єкти, які реалізують метод `Symbol.iterator`, як описано вище.
- *Псевдомасиви* -- це об'єкти, які мають індекси та `length`, тому вони виглядають як масиви.
- *Ітеровані* -- це об’єкти, які реалізують метод `Symbol.iterator`, як описано вище.
- *Псевдомасиви* -- це об’єкти, які мають індекси та `length`, тому вони виглядають як масиви.

Коли ми використовуємо JavaScript для практичних завдань у браузері або будь-якому іншому середовищі, ми можемо зустріти об'єкти, які є ітерованими або масивами, або обома.
Коли ми використовуємо JavaScript для практичних завдань у браузері або будь-якому іншому середовищі, ми можемо зустріти об’єкти, які є ітерованими або масивами, або обома.
Наприклад, рядки є ітерованими об’єктами (`for..of` працює на них) та псевдомасивами (у них є числові індекси та `length`).

Але ітерований об’єкт може не бути масивом. І навпаки, псевдомасив може бути не ітерованим об’єктом.

Наприклад, `range` у прикладі вище є ітерованим об’єктом, але не масивом, тому що він не має індексованих властивостей та `length`.

І ось об'єкт, який є псевдомасивом, але не ітерованим об’єктом:
І ось об’єкт, який є псевдомасивом, але не ітерованим об’єктом:

```js run
let arrayLike = { // має індекси та length => псевдомасив
Expand All @@ -191,7 +191,7 @@ for (let item of arrayLike) {}
*/!*
```

Обидва, ітерований об’єкт та псевдомасив, як правило є *не масивами*, вони не мають `push`,` pop` та ін. Це досить незручно, якщо у нас є такий об’єкт і ми хочемо працювати з ним як з масивом. НаприкладМи хотіли б працювати з `angy` за допомогою методів масиву. Як цього досягти?
Обидва, ітерований об’єкт та псевдомасив, як правило є *не масивами*, вони не мають `push`,` pop` та ін. Це досить незручно, якщо у нас є такий об’єкт і ми хочемо працювати з ним як з масивом. Наприклад, ми хотіли б працювати з `angy` за допомогою методів масиву. Як цього досягти?

## Array.from

Expand All @@ -212,7 +212,7 @@ let arr = Array.from(arrayLike); // (*)
alert(arr.pop()); // Світ (метод працює)
```

`Array.from` у рядку `(*)` бере об'єкт, перевіряє його на ітерабельність або те, що це псевдомасив, потім створює новий масив і копіює до нього всі елементи.
`Array.from` у рядку `(*)` бере об’єкт, перевіряє його на ітерабельність або те, що це псевдомасив, потім створює новий масив і копіює до нього всі елементи.

Те ж саме відбувається і з ітерованим об’єктом:

Expand Down Expand Up @@ -270,7 +270,7 @@ alert(chars);

...Але це коротше.

Ми навіть можемо побудувати на ньому `slice`, що підтримує сутогатні пари:
Ми навіть можемо побудувати на ньому `slice`, що підтримує сурогатні пари:

```js run
function slice(str, start, end) {
Expand All @@ -288,18 +288,18 @@ alert( str.slice(1, 3) ); // сміття (дві частини з різних

## Підсумки

Об'єкти, які можна використовуватися у `for..of`, називаються *ітерованими*.
Об’єкти, які можна використовуватися у `for..of`, називаються *ітерованими*.

- Технічно ітеровані об’єкти повинні реалізовувати метод з назвою `Symbol.iterator`.
- Результат `obj[Symbol.iterator]()` називається *ітератором*. Він забезпечує подальший процес ітерації.
- An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value.
- Ітератор повинен мати метод з назвою `next()`, який повертає об'єкт `{done: Boolean, value: any}`, де `done: true` означає кінець процесу ітерації, інакше `value` є наступним значенням.
- Ітератор повинен мати метод з назвою `next()`, який повертає об’єкт `{done: Boolean, value: any}`, де `done: true` означає кінець процесу ітерації, інакше `value` є наступним значенням.
- Метод `Symbol.iterator` автоматично викликається `for..of`, але ми також можемо це зробити безпосередньо.
- Вбудовані ітеровані об’єкти, такі як рядки або масиви, також реалізують `Symbol.iterator`.
- Рядковий ітератор знає про сурогатні пари.


Об'єкти, які мають індексовані властивості та `length`, називаються *псевдомасивами*. Такі об’єкти також можуть мати інші властивості та методи, але не мають вбудованих методів масивів.
Об’єкти, які мають індексовані властивості та `length`, називаються *псевдомасивами*. Такі об’єкти також можуть мати інші властивості та методи, але не мають вбудованих методів масивів.

Якщо ми заглянемо в специфікацію -- ми побачимо, що більшість вбудованих методів припускають, що вони працюють з ітерованими об’єктами або псевдомасивами замість "реальних" масивів, тому що це більш абстрактно.

Expand Down