aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/iteration_protocols/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/uk/web/javascript/reference/iteration_protocols/index.html')
-rw-r--r--files/uk/web/javascript/reference/iteration_protocols/index.html352
1 files changed, 352 insertions, 0 deletions
diff --git a/files/uk/web/javascript/reference/iteration_protocols/index.html b/files/uk/web/javascript/reference/iteration_protocols/index.html
new file mode 100644
index 0000000000..d5899043ca
--- /dev/null
+++ b/files/uk/web/javascript/reference/iteration_protocols/index.html
@@ -0,0 +1,352 @@
+---
+title: Протоколи перебору
+slug: Web/JavaScript/Reference/Протоколи_перебору
+tags:
+ - ECMAScript 2015
+ - JavaScript
+ - Ітератор
+ - ітерабельний об'єкт
+translation_of: Web/JavaScript/Reference/Iteration_protocols
+---
+<div>{{jsSidebar("More")}}</div>
+
+<p>Пара доповнень до ECMAScript 2015 є не новими вбудованими елементами чи синтаксисом, а протоколами. Ці протоколи можуть реалізовуватись будь-яким об'єктом, що відповідає певним правилам.</p>
+
+<p>Існують два протоколи: <a href="#Протокол_перебируваного">протокол ітерабельного об'єкта</a> і <a href="#Протокол_перебирача">протокол ітератора</a>.</p>
+
+<h2 id="Протокол_ітерабельного_обєкта">Протокол ітерабельного об'єкта</h2>
+
+<p>Протокол <strong>ітерабельного об'єкта</strong> дозволяє об'єктам JavaScript визначати чи налаштовувати свою ітераційну поведінку, наприклад, через які значення буде проходити цикл у конструкції {{jsxref("Statements/for...of", "for..of")}}. Деякі вбудовані типи є <a href="#Built-in_iterables">вбудованими ітерабельними об'єктами</a> з визначеною за замовчуванням ітераційною поведінкою, наприклад, {{jsxref("Array")}} або {{jsxref("Map")}}, в той час, як інші типи (такі, як {{jsxref("Object")}}) не є ітерабельними.</p>
+
+<p>Для того, щоб бути <strong>ітерабельним</strong>, об'єкт має реалізувати метод <strong>@@iterator</strong>, тобто, цей об'єкт (або один з об'єктів у його <a href="/uk/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">ланцюжку прототипів</a>) повинен мати властивість з ключем <strong>@@iterator</strong>, доступну через константу <code>{{jsxref("Symbol.iterator")}}</code>:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Властивість</th>
+ <th scope="col">Значення</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>[Symbol.iterator]</code></td>
+ <td>Функція без аргументів, яка повертає об'єкт, що відповідає <a href="#The_iterator_protocol">протоколу ітератора</a>.</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Коли виникає необхідність перебрати об'єкт (наприклад, на початку циклу <code>for..of</code>), його метод <code>@@iterator</code> викликається без аргументів, а <strong>ітератор</strong>, який він повертає, використовується для отримання значень, що перебираються.</p>
+
+<h2 id="Протокол_ітератора">Протокол ітератора</h2>
+
+<p>Протокол <strong>ітератора</strong> визначає стандартний спосіб створювати послідовності значень (скінченні або нескінченні).</p>
+
+<p>Об'єкт є ітератором, коли реалізує метод <code><strong>next()</strong></code> з наступною семантикою:</p>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Властивість</th>
+ <th scope="col">Значення</th>
+ </tr>
+ <tr>
+ <td><code>next</code></td>
+ <td>
+ <p>Функція з нулем аргументів, яка повертає об'єкт з двома властивостями:</p>
+
+ <ul>
+ <li><code>done</code> (булеве значення)
+
+ <ul>
+ <li>Має значення <code>true</code>, якщо ітератор досяг кінця послідовності, що перебирається. В цьому випадку <code>value</code> може містити <em>значення, що повертається</em> ітератором. Значення, що повертаються, пояснюються <a href="http://www.2ality.com/2013/06/iterators-generators.html#generators-as-threads">тут</a>.</li>
+ <li>Має значення <code>false</code>, якщо ітератор був здатний надати наступне значення послідовності. Це аналогічно тому, щоб взагалі не вказувати значення властивості <code>done</code>.</li>
+ </ul>
+ </li>
+ <li><code>value</code> - будь-яке значення JavaScript, що повертає ітератор. Його можна не вказувати, коли <code>done</code> дорівнює <code>true</code>.</li>
+ </ul>
+
+ <p>Метод <code>next</code> завжди повинен повертати об'єкт з належними властивостями, в тому числі <code>done</code> та <code>value</code>. Якщо повертається значення, що не є об'єктом (наприклад, <code>false</code> чи <code>undefined</code>), буде викинуто помилку {{jsxref("TypeError")}} ("iterator.next() returned a non-object value").</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="blockIndicator note">
+<p>Неможливо знати, чи певний об'єкт реалізує протокол ітератора, однак, можна легко створити об'єкт, який відповідає обом протоколам, ітератора та ітерабельного об'єкта (як показано нижче у прикладі). Це дозволяє використовувати ітератор там, де очікується ітерабельний об'єкт. Тому нечасто є потреба реалізовувати протокол ітератора, не реалізуючи також протокол ітерабельного об'єкта. </p>
+
+<pre><code>var myIterator = {
+ next: function() {
+ // ...
+ },
+ [Symbol.iterator]: function() { return this }
+};</code>
+</pre>
+</div>
+
+<h2 id="Приклади_застосування_протоколів_перебору">Приклади застосування протоколів перебору</h2>
+
+<p>Об'єкт {{jsxref("String")}} є прикладом вбудованого ітерабельного об'єкта:</p>
+
+<pre class="brush: js">var someString = '13';
+typeof someString[Symbol.iterator]; // "function"
+</pre>
+
+<p><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/String/@@iterator">Вбудований ітератор </a>об'єкта <code>String</code> повертає коди символів рядка один за одним:</p>
+
+<pre class="brush: js">var iterator = someString[Symbol.iterator]();
+iterator + ''; // "[object String Iterator]"
+
+iterator.next(); // { value: "1", done: false }
+iterator.next(); // { value: "3", done: false }
+iterator.next(); // { value: undefined, done: true }</pre>
+
+<p>Деякі вбудовані конструкції, такі як <a href="/uk/docs/Web/JavaScript/Reference/Operators/Spread_syntax">оператор розпакування</a>, використовують під капотом той самий протокол перебору:</p>
+
+<pre class="brush: js">[...someString] // ["1", "3"]</pre>
+
+<p>Ми можемо перевизначити поведінку під час перебору, надавши свій власний метод <code>@@iterator</code>:</p>
+
+<pre class="brush: js">var someString = new String('привіт'); // необхідно явно конструювати об'єкт String, щоб запобігти автопакуванню
+
+someString[Symbol.iterator] = function() {
+ return { // це ітератор, що повертає єдиний елемент, рядок "бувай"
+ next: function() {
+ if (this._first) {
+ this._first = false;
+ return { value: 'бувай', done: false };
+ } else {
+ return { done: true };
+ }
+ },
+ _first: true
+ };
+};
+</pre>
+
+<p>Зверніть увагу, як перевизначення методу <code>@@iterator</code> впливає на поведінку вбудованих конструкцій, що використовують протокол перебору:</p>
+
+<pre class="brush: js">[...someString]; // ["бувай"]
+someString + ''; // "привіт"
+</pre>
+
+<h2 id="Приклади_ітерабельних_обєктів">Приклади ітерабельних об'єктів</h2>
+
+<h3 id="Вбудовані_ітерабельні_обєкти">Вбудовані ітерабельні об'єкти</h3>
+
+<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} та {{jsxref("Set")}} всі є вбудованими ітерабельними об'єктами, тому що кожний з їхніх прототипів реалізує метод <code>@@</code><code>iterator</code>.</p>
+
+<h3 id="Створені_користувачем_ітерабельні_обєкти">Створені користувачем ітерабельні об'єкти</h3>
+
+<p>Ми можемо створювати власні ітерабельні об'єкти наступним чином:</p>
+
+<pre class="brush: js">var myIterable = {};
+myIterable[Symbol.iterator] = function* () {
+ yield 1;
+ yield 2;
+ yield 3;
+};
+[...myIterable]; // [1, 2, 3]
+</pre>
+
+<h3 id="Вбудовані_API_що_приймають_ітерабельні_обєкти">Вбудовані API, що приймають ітерабельні об'єкти</h3>
+
+<p>Існує багато API, які приймають ітерабельні об'єкти, наприклад: {{jsxref("Map", "Map([iterable])")}}, {{jsxref("WeakMap", "WeakMap([iterable])")}}, {{jsxref("Set", "Set([iterable])")}} and {{jsxref("WeakSet", "WeakSet([iterable])")}}:</p>
+
+<pre class="brush: js">var myObj = {};
+new Map([[1, 'а'], [2, 'б'], [3, 'в']]).get(2); // "б"
+new WeakMap([[{}, 'а'], [myObj, 'б'], [{}, 'в']]).get(myObj); // "б"
+new Set([1, 2, 3]).has(3); // true
+new Set('123').has('2'); // true
+new WeakSet(function* () {
+ yield {};
+ yield myObj;
+ yield {};
+}()).has(myObj); // true
+</pre>
+
+<p>Дивіться також {{jsxref("Promise.all", "Promise.all(iterable)")}}, {{jsxref("Promise.race", "Promise.race(iterable)")}} та {{jsxref("Array.from", "Array.from()")}}.</p>
+
+<h3 id="Синтаксис_що_очікує_на_ітерабельний_обєкт">Синтаксис, що очікує на ітерабельний об'єкт</h3>
+
+<p>Деякі оператори та вирази очікують на ітерабельні об'єкти, наприклад, цикли <code><a href="/uk/docs/Web/JavaScript/Reference/Statements/for...of">for-of</a></code>, <a href="/uk/docs/Web/JavaScript/Reference/Operators/Spread_syntax">оператор розпакування</a>, <code><a href="/uk/docs/Web/JavaScript/Reference/Operators/yield*">yield*</a></code> та <a href="/uk/docs/Web/JavaScript/Reference/Operators/Деструктуризація">деструктуризаційне присвоєння</a>:</p>
+
+<pre class="brush: js">for(let value of ['а', 'б', 'в']){
+ console.log(value);
+}
+// "а"
+// "б"
+// "в"
+
+[...'абв']; // ["а", "б", "в"]
+
+function* gen() {
+ yield* ['а', 'б', 'в'];
+}
+
+gen().next(); // { value:"а", done:false }
+
+[a, b, c] = new Set(['а', 'б', 'в']);
+a // "а"
+
+</pre>
+
+<h3 id="Погано_сформовані_ітерабельні_обєкти">Погано сформовані ітерабельні об'єкти</h3>
+
+<p>Якщо метод ітерабельного об'єкта <code>@@iterator</code> не повертає об'єкт ітератора, то це погано сформований ітерабельний об'єкт. Використання його в такому вигляді ймовірно призведе до викидання винятків під час виконання або помилкової поведінки:</p>
+
+<pre class="brush: js">var nonWellFormedIterable = {}
+nonWellFormedIterable[Symbol.iterator] = () =&gt; 1
+[...nonWellFormedIterable] // TypeError: [] is not a function
+</pre>
+
+<h2 id="Приклади_ітераторів">Приклади ітераторів</h2>
+
+<h3 id="Простий_ітератор">Простий ітератор</h3>
+
+<pre class="brush: js">function makeIterator(array) {
+ var nextIndex = 0;
+
+ return {
+ next: function() {
+ return nextIndex &lt; array.length ?
+ {value: array[nextIndex++], done: false} :
+ {done: true};
+ }
+ };
+}
+
+var it = makeIterator(['yo', 'ya']);
+
+console.log(it.next().value); // 'yo'
+console.log(it.next().value); // 'ya'
+console.log(it.next().done); // true
+</pre>
+
+<h3 id="Нескінченний_ітератор">Нескінченний ітератор</h3>
+
+<pre class="brush: js">function idMaker() {
+ var index = 0;
+
+ return {
+ next: function(){
+ return {value: index++, done: false};
+ }
+ };
+}
+
+var it = idMaker();
+
+console.log(it.next().value); // '0'
+console.log(it.next().value); // '1'
+console.log(it.next().value); // '2'
+// ...
+</pre>
+
+<h3 id="З_генератором">З генератором</h3>
+
+<pre class="brush: js">function* makeSimpleGenerator(array) {
+ var nextIndex = 0;
+
+ while (nextIndex &lt; array.length) {
+ yield array[nextIndex++];
+ }
+}
+
+var gen = makeSimpleGenerator(['yo', 'ya']);
+
+console.log(gen.next().value); // 'yo'
+console.log(gen.next().value); // 'ya'
+console.log(gen.next().done); // true
+
+
+
+function* idMaker() {
+ var index = 0;
+ while (true)
+ yield index++;
+}
+
+var gen = idMaker();
+
+console.log(gen.next().value); // '0'
+console.log(gen.next().value); // '1'
+console.log(gen.next().value); // '2'
+// ...
+</pre>
+
+<h3 id="З_класом_ES2015">З класом ES2015</h3>
+
+<pre class="brush: js">class SimpleClass {
+ constructor(data) {
+ this.index = 0;
+ this.data = data;
+ }
+
+ [Symbol.iterator]() {
+ return {
+ next: () =&gt; {
+ if (this.index &lt; this.data.length) {
+ return {value: this.data[this.index++], done: false};
+ } else {
+ this.index = 0; //Якщо ми хотіли б перебрати його знову, без примусового ручного оновлення індексу
+ return {done: true};
+ }
+ }
+ }
+ };
+}
+
+const simple = new SimpleClass([1,2,3,4,5]);
+
+for (const val of simple) {
+ console.log(val); //'0' '1' '2' '3' '4' '5'
+}
+</pre>
+
+<h2 id="Генератор_є_ітератором_чи_ітерабельним_обєктом">Генератор є ітератором чи ітерабельним об'єктом?</h2>
+
+<p><a href="/uk/docs/Web/JavaScript/Reference/Global_Objects/Generator">Об'єкт генератор</a> є одночасно ітератором та ітерабельним об'єктом:</p>
+
+<pre class="brush: js">var aGeneratorObject = function* () {
+ yield 1;
+ yield 2;
+ yield 3;
+}();
+typeof aGeneratorObject.next;
+// "function", бо він має метод next, отже, він ітератор
+typeof aGeneratorObject[Symbol.iterator];
+// "function", бо він має метод @@iterator, отже, він ітерабельний об'єкт
+aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
+// true, бо його метод @@iterator повертає себе (ітератор),
+// отже, він добре сформований ітерабельний об'єкт
+[...aGeneratorObject];
+// [1, 2, 3]
+</pre>
+
+<h2 id="Специфікації">Специфікації</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Специфікація</th>
+ <th scope="col">Статус</th>
+ <th scope="col">Коментар</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES2015', '#sec-iteration', 'Iteration')}}</td>
+ <td>{{Spec2('ES2015')}}</td>
+ <td>Початкова виознака.</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-iteration', 'Iteration')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Див._також">Див. також</h2>
+
+<ul>
+ <li>Більше інформації щодо генераторів ES2015 дивіться у <a href="/uk/docs/Web/JavaScript/Reference/Statements/function*">документації по function*</a>.</li>
+</ul>