Ð ÑовÑеменнÑй JavaScript добавлена Ð½Ð¾Ð²Ð°Ñ ÐºÐ¾Ð½ÑепÑÐ¸Ñ Â«Ð¸ÑеÑиÑÑемÑÑ Â» (iterable) обÑекÑов.
ÐÑеÑиÑÑемÑе или, инÑми Ñловами, «пеÑебиÑаемÑе» обÑекÑÑ â ÑÑо Ñе, ÑодеÑжимое коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑебÑаÑÑ Ð² Ñикле.
ÐапÑимеÑ, пеÑебиÑаемÑм обÑекÑом ÑвлÑеÑÑÑ Ð¼Ð°ÑÑив. Ðо не ÑолÑко он. РбÑаÑзеÑе ÑÑÑеÑÑвÑÐµÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво обÑекÑов, коÑоÑÑе не ÑвлÑÑÑÑÑ Ð¼Ð°ÑÑивами, но ÑодеÑжимое коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑебÑаÑÑ (к пÑимеÑÑ, ÑпиÑок DOM-Ñзлов).
ÐÐ»Ñ Ð¿ÐµÑебоÑа ÑакиÑ
обÑекÑов добавлен новÑй ÑинÑакÑÐ¸Ñ Ñикла: for..of.
ÐапÑимеÑ:
'use strict';
let arr = [1, 2, 3]; // маÑÑив â пÑÐ¸Ð¼ÐµÑ Ð¸ÑеÑиÑÑемого обÑекÑа
for (let value of arr) {
alert(value); // 1, заÑем 2, заÑем 3
}
Также иÑеÑиÑÑемой ÑвлÑеÑÑÑ ÑÑÑока:
'use strict';
for (let char of "ÐÑивеÑ") {
alert(char); // ÐÑÐ²ÐµÐ´ÐµÑ Ð¿Ð¾ одной бÑкве: Ð, Ñ, и, в, е, Ñ
}
ÐÑеÑаÑоÑÑ â ÑаÑÑиÑÑÑÑÐ°Ñ Ð¿Ð¾Ð½ÑÑие «маÑÑив» конÑепÑиÑ, коÑоÑÐ°Ñ Ð¿ÑонизÑÐ²Ð°ÐµÑ ÑовÑеменнÑй ÑÑандаÑÑ JavaScript ÑвеÑÑ Ñ Ð´Ð¾Ð½Ð¸Ð·Ñ.
ÐÑакÑиÑеÑки везде, где нÑжен пеÑебоÑ, он оÑÑÑеÑÑвлÑеÑÑÑ ÑеÑез иÑеÑаÑоÑÑ. ÐÑо вклÑÑÐ°ÐµÑ Ð² ÑÐµÐ±Ñ Ð½Ðµ ÑолÑко ÑÑÑоки, маÑÑивÑ, но и вÑзов ÑÑнкÑии Ñ Ð¾Ð¿ÐµÑаÑоÑом spread f(...args), и многое дÑÑгое.
РоÑлиÑие Ð¾Ñ Ð¼Ð°ÑÑивов, «пеÑебиÑаемÑе» обÑекÑÑ Ð¼Ð¾Ð³ÑÑ Ð½Ðµ имеÑÑ Â«Ð´Ð»Ð¸Ð½Ñ» length. Ðак Ð¼Ñ Ñвидим далее, иÑеÑаÑоÑÑ Ð´Ð°ÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ ÑделаÑÑ Â«Ð¿ÐµÑебиÑаемÑми» лÑбÑе обÑекÑÑ.
Свой иÑеÑаÑоÑ
ÐопÑÑÑим, Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð½ÐµÐºÐ¸Ð¹ обÑекÑ, коÑоÑÑй надо «ÑмнÑм ÑпоÑобом» пеÑебÑаÑÑ.
ÐапÑимеÑ, range â диапазон ÑиÑел Ð¾Ñ from до to, и Ð¼Ñ Ñ
оÑим, ÑÑÐ¾Ð±Ñ for (let num of range) «пеÑебиÑал» ÑÑÐ¾Ñ Ð¾Ð±ÑекÑ. ÐÑи ÑÑом под пеÑебоÑом Ð¼Ñ Ð¿Ð¾Ð´ÑазÑмеваем пеÑеÑиÑление ÑиÑел Ð¾Ñ from до to.
ÐбÑÐµÐºÑ range без иÑеÑаÑоÑа:
let range = {
from: 1,
to: 5
};
// Ñ
оÑим ÑделаÑÑ Ð¿ÐµÑебоÑ
// for (let num of range) ...
ÐÐ»Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑи иÑполÑзоваÑÑ Ð¾Ð±ÑÐµÐºÑ Ð² for..of нÑжно ÑоздаÑÑ Ð² нÑм ÑвойÑÑво Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ Symbol.iterator (ÑиÑÑемнÑй Ñимвол).
ÐÑи вÑзове меÑода Symbol.iterator пеÑебиÑаемÑй обÑÐµÐºÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ возвÑаÑаÑÑ Ð´ÑÑгой обÑÐµÐºÑ («иÑеÑаÑоÑ»), коÑоÑÑй ÑÐ¼ÐµÐµÑ Ð¾ÑÑÑеÑÑвлÑÑÑ Ð¿ÐµÑебоÑ.
Ðо ÑÑандаÑÑÑ Ñ Ñакого обÑекÑа должен бÑÑÑ Ð¼ÐµÑод next(), коÑоÑÑй пÑи каждом вÑзове возвÑаÑÐ°ÐµÑ Ð¾ÑеÑедное знаÑение и пÑовеÑÑеÑ, оконÑен ли пеÑебоÑ.
Ркоде ÑÑо вÑглÑÐ´Ð¸Ñ ÑледÑÑÑим обÑазом:
'use strict';
let range = {
from: 1,
to: 5
}
// Ñделаем обÑÐµÐºÑ range иÑеÑиÑÑемÑм
range[Symbol.iterator] = function() {
let current = this.from;
let last = this.to;
// меÑод должен веÑнÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ð¼ÐµÑодом next()
return {
next() {
if (current <= last) {
return {
done: false,
value: current++
};
} else {
return {
done: true
};
}
}
}
};
for (let num of range) {
alert(num); // 1, заÑем 2, 3, 4, 5
}
Ðак видно из кода вÑÑе, здеÑÑ Ð¸Ð¼ÐµÐµÑ Ð¼ÐµÑÑо Ñазделение ÑÑÑноÑÑей:
- ÐеÑебиÑаемÑй обÑекÑ
rangeÑам не ÑеализÑÐµÑ Ð¼ÐµÑÐ¾Ð´Ñ Ð´Ð»Ñ Ñвоего пеÑебоÑа. - ÐÐ»Ñ ÑÑого ÑоздаÑÑÑÑ Ð´ÑÑгой обÑекÑ, коÑоÑÑй Ñ
ÑÐ°Ð½Ð¸Ñ ÑекÑÑее ÑоÑÑоÑние пеÑебоÑа и возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение. ÐÑÐ¾Ñ Ð¾Ð±ÑÐµÐºÑ Ð½Ð°Ð·ÑваеÑÑÑ Ð¸ÑеÑаÑоÑом и возвÑаÑаеÑÑÑ Ð¿Ñи вÑзове меÑода
range[Symbol.iterator]. - У иÑеÑаÑоÑа должен бÑÑÑ Ð¼ÐµÑод
next(), коÑоÑÑй пÑи каждом вÑзове возвÑаÑÐ°ÐµÑ Ð¾Ð±ÑÐµÐºÑ Ñо ÑвойÑÑвами:valueâ оÑеÑедное знаÑение,doneâ ÑавноfalseеÑли еÑÑÑ ÐµÑÑ Ð·Ð½Ð°ÑениÑ, иtrueâ в конÑе.
ÐонÑÑÑÑкÑÐ¸Ñ for..of в наÑале Ñвоего вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð°Ð²ÑомаÑиÑеÑки вÑзÑÐ²Ð°ÐµÑ Symbol.iterator(), полÑÑÐ°ÐµÑ Ð¸ÑеÑаÑÐ¾Ñ Ð¸ далее вÑзÑÐ²Ð°ÐµÑ Ð¼ÐµÑод next() до полÑÑÐµÐ½Ð¸Ñ done: true. Такова внÑÑÑеннÑÑ Ð¼ÐµÑ
аника. ÐнеÑний код пÑи пеÑебоÑе ÑеÑез for..of Ð²Ð¸Ð´Ð¸Ñ ÑолÑко знаÑениÑ.
Такое оÑделение ÑÑнкÑионалÑноÑÑи пеÑебоÑа Ð¾Ñ Ñамого обÑекÑа даÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑÑ Ð³Ð¸Ð±ÐºÐ¾ÑÑÑ. ÐапÑимеÑ, обÑÐµÐºÑ Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ ÑазнÑе иÑеÑаÑоÑÑ Ð² завиÑимоÑÑи Ð¾Ñ Ñвоего наÑÑÑÐ¾ÐµÐ½Ð¸Ñ Ð¸ вÑемени ÑÑÑок. Ðднако, бÑваÑÑ ÑиÑÑаÑии когда оно не нÑжно.
ÐÑли ÑÑнкÑионалÑноÑÑÑ Ð¿Ð¾ пеÑебоÑÑ (меÑод next) пÑедоÑÑавлÑеÑÑÑ Ñамим обÑекÑом, Ñо можно веÑнÑÑÑ this в каÑеÑÑве иÑеÑаÑоÑа:
'use strict';
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
return this;
},
next() {
if (this.current === undefined) {
// иниÑиализаÑÐ¸Ñ ÑоÑÑоÑÐ½Ð¸Ñ Ð¸ÑеÑаÑии
this.current = this.from;
}
if (this.current <= this.to) {
return {
done: false,
value: this.current++
};
} else {
// оÑиÑÑка ÑекÑÑей иÑеÑаÑии
delete this.current;
return {
done: true
};
}
}
};
for (let num of range) {
alert(num); // 1, заÑем 2, 3, 4, 5
}
// ÐÑоизойдÑÑ Ð²Ñзов Math.max(1,2,3,4,5);
alert( Math.max(...range) ); // 5 (*)
ÐÑи Ñаком Ð¿Ð¾Ð´Ñ Ð¾Ð´Ðµ Ñам обÑÐµÐºÑ Ð¸ Ñ ÑÐ°Ð½Ð¸Ñ ÑоÑÑоÑние иÑеÑаÑии (ÑекÑÑий пеÑебиÑаемÑй ÑлеменÑ).
Рданном ÑлÑÑае ÑÑо ÑабоÑаеÑ, но Ð´Ð»Ñ Ð±Ð¾Ð»ÑÑей гибкоÑÑи и понÑÑноÑÑи кода ÑекомендÑеÑÑÑ, вÑÑ Ð¶Ðµ, вÑделÑÑÑ Ð¸ÑеÑаÑÐ¾Ñ Ð² оÑделÑнÑй обÑÐµÐºÑ Ñо Ñвоим ÑоÑÑоÑнием и кодом.
... и иÑеÑаÑоÑÑРпоÑледней ÑÑÑоке (*) пÑимеÑа вÑÑе можно видеÑÑ, ÑÑо иÑеÑиÑÑемÑй обÑÐµÐºÑ Ð¿ÐµÑедаÑÑÑÑ ÑеÑез spread Ð´Ð»Ñ Math.max.
ÐÑи ÑÑом ...range инÑеÑпÑеÑиÑÑеÑÑÑ ÐºÐ°Ðº поÑледоваÑелÑноÑÑÑ ÑиÑел. То еÑÑÑ Ð¿ÑоизойдÑÑ Ñикл for..of по range, и его ÑезÑлÑÑаÑÑ Ð±ÑдÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð² каÑеÑÑве ÑпиÑка аÑгÑменÑов.
ÐÐ¾Ð·Ð¼Ð¾Ð¶Ð½Ñ Ð¸ беÑконеÑнÑе иÑеÑаÑоÑÑ. ÐапÑимеÑ, пÑÐ¸Ð¼ÐµÑ Ð²ÑÑе пÑи range.to = Infinity бÑÐ´ÐµÑ ÑаковÑм. Ðли можно ÑделаÑÑ Ð¸ÑеÑаÑоÑ, генеÑиÑÑÑÑий беÑконеÑнÑÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð¿ÑевдоÑлÑÑайнÑÑ
ÑиÑел. Тоже полезно.
ÐÐµÑ Ð½Ð¸ÐºÐ°ÐºÐ¸Ñ
огÑаниÑений на next, он Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð²ÑÑ Ð½Ð¾Ð²Ñе и новÑе знаÑениÑ, и ÑÑо ноÑмалÑно.
РазÑмееÑÑÑ, Ñикл for..of по ÑÐ°ÐºÐ¾Ð¼Ñ Ð¸ÑеÑаÑоÑÑ Ñоже бÑÐ´ÐµÑ Ð±ÐµÑконеÑнÑм, нÑжно его пÑеÑÑваÑÑ, напÑимеÑ, ÑеÑез break.
ÐÑÑÑоеннÑе иÑеÑаÑоÑÑ
ÐÑÑÑоеннÑе в JavaScript иÑеÑаÑоÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð¸ ÑвнÑм обÑазом, без for..of, пÑÑмÑм вÑзовом Symbol.iterator.
ÐапÑимеÑ, ÑÑÐ¾Ñ ÐºÐ¾Ð´ полÑÑÐ°ÐµÑ Ð¸ÑеÑаÑÐ¾Ñ Ð´Ð»Ñ ÑÑÑоки и вÑзÑÐ²Ð°ÐµÑ ÐµÐ³Ð¾ полноÑÑÑÑ Â«Ð²ÑÑÑнÑÑ»:
'use strict';
let str = "Hello";
// ÐÐµÐ»Ð°ÐµÑ Ñо же, ÑÑо и
// for (var letter of str) alert(letter);
let iterator = str[Symbol.iterator]();
while(true) {
let result = iterator.next();
if (result.done) break;
alert(result.value); // ÐÑÐ²ÐµÐ´ÐµÑ Ð²Ñе бÑÐºÐ²Ñ Ð¿Ð¾ оÑеÑеди
}
То же Ñамое бÑÐ´ÐµÑ ÑабоÑаÑÑ Ð¸ Ð´Ð»Ñ Ð¼Ð°ÑÑивов.
ÐÑого
- ÐÑеÑаÑÐ¾Ñ â обÑекÑ, пÑедназнаÑеннÑй Ð´Ð»Ñ Ð¿ÐµÑебоÑа дÑÑгого обÑекÑа.
- У иÑеÑаÑоÑа должен бÑÑÑ Ð¼ÐµÑод
next(), возвÑаÑаÑÑий обÑекÑ{done: Boolean, value: any}, гдеvalueâ оÑеÑедное знаÑение, аdone: trueв конÑе. - ÐеÑод
Symbol.iteratorпÑедназнаÑен Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¸ÑеÑаÑоÑа из обÑекÑа. Циклfor..ofÐ´ÐµÐ»Ð°ÐµÑ ÑÑо авÑомаÑиÑеÑки, но можно и вÑзваÑÑ ÐµÐ³Ð¾ напÑÑмÑÑ. - Ð ÑовÑеменном ÑÑандаÑÑе еÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ меÑÑ, где вмеÑÑо маÑÑива иÑполÑзÑÑÑÑÑ Ð±Ð¾Ð»ÐµÐµ абÑÑÑакÑнÑе «иÑеÑиÑÑемÑе» (Ñо ÑвойÑÑвом
Symbol.iterator) обÑекÑÑ, напÑÐ¸Ð¼ÐµÑ Ð¾Ð¿ÐµÑаÑÐ¾Ñ spread.... - ÐÑÑÑоеннÑе обÑекÑÑ, Ñакие как маÑÑÐ¸Ð²Ñ Ð¸ ÑÑÑоки, ÑвлÑÑÑÑÑ Ð¸ÑеÑиÑÑемÑми, в ÑооÑвеÑÑÑвии Ñ Ð¾Ð¿Ð¸ÑаннÑм вÑÑе.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)