Ðдно из нововведений ÑÑандаÑÑа ECMAScript 2015 - пÑоÑÐ¾ÐºÐ¾Ð»Ñ Ð¿ÐµÑебоÑа, коÑоÑÑе могÑÑ ÑÐµÐ°Ð»Ð¸Ð·Ð¾Ð²Ð°Ð½Ñ Ð»ÑбÑм обÑекÑом, ÑоблÑÐ´Ð°Ñ Ð¿Ñи ÑÑом опÑеделÑннÑе пÑавила.
ÐÑоÑÐ¾ÐºÐ¾Ð»Ñ Ð¿ÐµÑебоÑаÐÑоÑÐ¾ÐºÐ¾Ð»Ñ Ð¿ÐµÑебоÑа вклÑÑаÑÑ the "iterable" protocol и the "iterator" protocol.
ÐÑоÑокол "ÐÑеÑиÑÑемÑй"ÐÑоÑокол "ÐÑеÑиÑÑемÑй" позволÑÐµÑ JavaScript обÑекÑам опÑеделÑÑÑ Ð¸Ð»Ð¸ наÑÑÑаиваÑÑ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ пеÑебоÑа, напÑимеÑ, Ñо какие знаÑÐµÐ½Ð¸Ñ Ð¿ÐµÑебиÑаÑÑÑÑ Ð² конÑÑÑÑкÑии for..of
. ÐекоÑоÑÑе вÑÑÑоеннÑе ÑипÑ, Ñакие как Array
или Map
, имеÑÑ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ пеÑебоÑа по ÑмолÑаниÑ, в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº дÑÑгие ÑÐ¸Ð¿Ñ (Ñакие как Object
) его не имеÑÑ
ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¾Ð±ÑÐµÐºÑ Ð±Ñл иÑеÑиÑÑемÑм, в нем должен бÑÑÑ Ñеализован меÑод @@iterator, Ñ.е. ÑÑÐ¾Ñ Ð¾Ð±ÑÐµÐºÑ (или лÑбой из обÑекÑов из его prototype chain) должен имеÑÑ ÑвойÑÑво Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Symbol
.iterator
:
[Symbol.iterator]
ФÑнкÑÐ¸Ñ Ð±ÐµÐ· аÑгÑменÑов, возвÑаÑаÑÑÐ°Ñ Ð¾Ð±ÑекÑ, ÑооÑвеÑÑÑвÑÑÑий iterator protocol.
ÐÑÑкий Ñаз, когда обÑÐµÐºÑ Ð¿Ð¾Ð´Ð»ÐµÐ¶Ð¸Ñ Ð¿ÐµÑебоÑÑ (напÑимеÑ, когда в коде вÑÑÑеÑаеÑÑÑ Ñикл for..of
), вÑзÑваеÑÑÑ ÐµÐ³Ð¾ меÑод @@iterator
без аÑгÑменÑов, и возвÑаÑаемÑй iterator иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¿ÐµÑебиÑаемÑÑ
знаÑений.
ÐÑоÑокол "ÐÑеÑаÑоÑ" опÑеделÑÐµÑ ÑÑандаÑÑнÑй ÑпоÑоб полÑÑÐµÐ½Ð¸Ñ Ð¿Ð¾ÑледоваÑелÑноÑÑи знаÑений (конеÑной или беÑконеÑной).
ÐбÑÐµÐºÑ ÑвлÑеÑÑÑ Ð¸ÑеÑаÑоÑом, еÑли в нем опÑеделÑн меÑод next() , ÑеализÑÑÑий ÑледÑÑÑÑÑ Ð»Ð¾Ð³Ð¸ÐºÑ:
СвойÑÑво ÐнаÑениеnext
ФÑнкÑÐ¸Ñ Ð±ÐµÐ· аÑгÑменÑов, возвÑаÑаÑÑÐ°Ñ Ð¾Ð±ÑÐµÐºÑ Ñ Ð´Ð²ÑÐ¼Ñ ÑвойÑÑвами:
done
(boolean)
true
еÑли иÑеÑаÑÐ¾Ñ Ð´Ð¾ÑÑиг конÑа иÑеÑиÑÑемой поÑледоваÑелÑноÑÑи. Ð ÑÑом ÑлÑÑае ÑвойÑÑво value
Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð¿ÑеделÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемое знаÑение иÑеÑаÑоÑа. ÐозвÑаÑаемÑе знаÑÐµÐ½Ð¸Ñ Ð¾Ð±ÑÑÑнÑÑÑÑÑ Ð±Ð¾Ð»ÐµÐµ подÑобно here.false
еÑли иÑеÑаÑÐ¾Ñ Ð¼Ð¾Ð¶ÐµÑ Ð³ÐµÐ½ÐµÑиÑоваÑÑ ÑледÑÑÑее знаÑение поÑледоваÑелÑноÑÑи. ÐÑо ÑквиваленÑно не ÑÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¼Ñ done.value
- лÑбое JavaScript знаÑение, возвÑаÑаемое иÑеÑаÑоÑом. ÐÐ¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¾Ð¿ÑÑено, еÑли done Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°Ñение
true
.ÐекоÑоÑÑе иÑеÑаÑоÑÑ, в ÑÐ²Ð¾Ñ Ð¾ÑеÑедÑ, иÑеÑабелÑнÑ:
var someArray = [1, 5, 7];
var someArrayEntries = someArray.entries();
someArrayEntries.toString(); // "[object Array Iterator]"
someArrayEntries === someArrayEntries[Symbol.iterator](); // true
ÐÑимеÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿ÑоÑокола "иÑеÑаÑоÑа"
String
ÑвлÑеÑÑÑ Ð¿ÑимеÑом вÑÑÑоенного иÑеÑабелÑного обÑекÑа:
var someString = "hi";
typeof someString[Symbol.iterator]; // "function"
Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ð¸ÑеÑаÑÐ¾Ñ ÑÑÑоки возвÑаÑÐ°ÐµÑ ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ ÑÑÑоки дÑÑг за дÑÑгом:
var iterator = someString[Symbol.iterator]();
iterator + ""; // "[object String Iterator]"
iterator.next(); // { value: "h", done: false }
iterator.next(); // { value: "i", done: false }
iterator.next(); // { value: undefined, done: true }
ÐекоÑоÑÑе вÑÑÑоеннÑе конÑÑÑÑкÑии ÑзÑка, напÑимеÑ, spread operator, иÑполÑзÑÑÑ Ð² Ñвоей внÑÑÑенней ÑеализаÑии ÑÐ¾Ñ Ð¶Ðµ пÑоÑокол иÑеÑаÑии:
[...someString]; // ["h", "i"]
Ðоведение иÑеÑаÑоÑа можно пеÑеопÑеделиÑÑ Ð¿Ñименив ÑобÑÑвеннÑй @@iterator
:
var someString = new String("hi"); // need to construct a String object explicitly to avoid auto-boxing
someString[Symbol.iterator] = function () {
return {
// this is the iterator object, returning a single element, the string "bye"
next: function () {
if (this._first) {
this._first = false;
return { value: "bye", done: false };
} else {
return { done: true };
}
},
_first: true,
};
};
Notice how redefining @@iterator
affects the behavior of built-in constructs, that use the iteration protocol:
[...someString]; // ["bye"]
someString + ""; // "hi"
ÐÑÑÑÐ¾ÐµÐ½Ð½Ð°Ñ Ð¸ÑеÑиÑÑемоÑÑÑ
String
, Array
, TypedArray
, Map
и Set
иÑеÑиÑÑемÑ, Ñак как иÑ
пÑоÑоÑÐ¸Ð¿Ñ ÑодеÑÐ¶Ð°Ñ @@iterator
меÑод, а Object
неÑ, Ñак как пÑоÑоÑип Object
не ÑодеÑÐ¶Ð¸Ñ Ð¼ÐµÑода @@iterator
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑоздаÑÑ Ð¸ÑеÑиÑÑемÑй обÑÐµÐºÑ Ñами:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable]; // [1, 2, 3]
Builtin APIs need iterables
Map([iterable])
, WeakMap([iterable])
, Set([iterable])
and WeakSet([iterable])
:
var myObj = {};
new Map([
[1, "a"],
[2, "b"],
[3, "c"],
]).get(2); // "b"
new WeakMap([
[{}, "a"],
[myObj, "b"],
[{}, "c"],
]).get(myObj); // "b"
new Set([1, 2, 3]).has(3); // true
new Set("123").has("2"); // true
new WeakSet(
(function* () {
yield {};
yield myObj;
yield {};
})(),
).has(myObj); // true
and Promise.all(iterable)
, Promise.race(iterable)
, Array.from()
for-of, spread, yield*, destructing - иÑполÑзование данного ÑинÑакÑиÑа возможно ÑолÑко еÑли ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ , к коÑоÑÑм он пÑименÑеÑÑÑ, иÑеÑиÑÑемÑ:
for (let value of ["a", "b", "c"]) {
console.log(value);
}
// "a"
// "b"
// "c"
[..."abc"]; // ["a", "b", "c"]
function* gen() {
yield* ["a", "b", "c"];
}
gen().next()[(a, b, c)] = // { value:"a", done:false }
new Set(["a", "b", "c"]);
a; // "a"
Non-well-formed iterables
If an iterable's @@iterator
method doesn't return an iterator object, then it's a non-well-formed iterable, using it as such is likely to result in runtime exceptions or buggy behavior:
var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
ÐбÑекÑ-генеÑаÑÐ¾Ñ ÑвлÑеÑÑÑ Ð¸ÑеÑаÑоÑом или иÑеÑиÑÑемÑм
Ð Ñем и дÑÑгим
var aGeneratorObject = function*(){
yield 1;
yield 2;
yield 3;
}()
typeof aGeneratorObject.next
// "function", because it has a next method, so it's an iterator
typeof aGeneratorObject[Symbol.iterator]
// "function", because it has an @@iterator method, so it's an iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject
// true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable
[...aGeneratorObject]
// [1, 2, 3]
ÐÑимеÑÑ ÐÑоÑÑой иÑеÑаÑоÑ
function makeIterator(array) {
var nextIndex = 0;
return {
next: function () {
return nextIndex < 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
ÐеÑконеÑнÑй иÑеÑаÑоÑ
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'
// ...
С генеÑаÑоÑом
function* makeSimpleGenerator(array) {
var nextIndex = 0;
while (nextIndex < 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'
// ...
СпеÑиÑикаÑии СмоÑÑиÑе Ñакже
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4