--- title: Iteration protocols slug: Web/JavaScript/Reference/Iteration_protocols translation_of: Web/JavaScript/Reference/Iteration_protocols ---
ECMAScript 2015 (ES6)에는 새로운 문법이나 built-in 뿐만이 아니라, protocols(표현법들)도 추가되었습니다. 이 protocol 은 일정 규칙만 충족한다면 어떠한 객체에 의해서도 구현될 수 있습니다.
2개의 protocol이 있습니다 : iterable protocol 과 iterator protocol.
iterable protocol 은 JavaScript 객체들이, 예를 들어 {{jsxref("Statements/for...of", "for..of")}} 구조에서 어떠한 value 들이 loop 되는 것과 같은 iteration 동작을 정의하거나 사용자 정의하는 것을 허용합니다. 다른 type 들({{jsxref("Object")}} 와 같은)이 그렇지 않은 반면에, 어떤 built-in type 들은 {{jsxref("Array")}} 또는 {{jsxref("Map")}} 과 같은 default iteration 동작으로 built-in iterables 입니다.
iterable 하기 위해서 object는 @@iterator 메소드를 구현해야 합니다. 이것은 object (또는 prototype chain 의 오브젝트 중 하나) 가 {{jsxref("Symbol.iterator")}}
key 의 속성을 가져야 한다는 것을 의미합니다 :
Property | Value |
---|---|
[Symbol.iterator] |
object를 반환하는, arguments 없는 function. iterator protocol 을 따른다. |
어떠한 객체가 반복(Iterate)되어야 한다면 이 객체의 @@iterator
메소드가 인수없이 호출되고, 반환된 iterator는 반복을 통해서 획득할 값들을 얻을 때 사용됩니다.
iterator protocol 은 value( finite 또는 infinite) 들의 sequence 를 만드는 표준 방법을 정의합니다.
객체가 next()
메소드를 가지고 있고, 아래의 규칙에 따라 구현되었다면 그 객체는 iterator이다:
Property | Value |
---|---|
next |
아래 2개의 속성들을 가진 object 를 반환하는 arguments 없는 함수 :
|
몇몇 iterator들은 iterable(반복 가능)이다:
var someArray = [1, 5, 7]; var someArrayEntries = someArray.entries(); someArrayEntries.toString(); // "[object Array Iterator]" someArrayEntries === someArrayEntries[Symbol.iterator](); // true
{{jsxref("String")}} 은 built-in iterable 객체의 한 예시입니다.
var someString = "hi"; typeof someString[Symbol.iterator]; // "function"
String
의 기본 iterator 는 string 의 문자를 하나씩 반환합니다.
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와 같은 특정 내장 구조(built-in constructs)들은 실제로는 동일한 iteration protocol을 사용한다:
[...someString] // ["h", "i"]
사용자만의 @@iterator
를 특정함으로써 원하는 반복 행위(iteration behavior)를 설정할 수 있다:
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 }; };
재설정된 @@iterator
가 어떻게 내장 구조(built-in constructs)의 반복 행위에 영향을 주는지 참고:
[...someString]; // ["bye"] someString + ""; // "hi"
{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} and {{jsxref("Set")}} 는 모두 내장 iterable이다. 이 객체들의 프로토타입 객체들은 모두 @@
iterator
메소드를 가지고 있기 때문이다.
이렇게 고유한 iterables 를 만들 수 있다.
var myIterable = {}; myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable]; // [1, 2, 3]
Iterable을 허용하는 많은 내장 API들이 있다. 예를 들어: {{jsxref("Map", "Map([iterable])")}}, {{jsxref("WeakMap", "WeakMap([iterable])")}}, {{jsxref("Set", "Set([iterable])")}} and {{jsxref("WeakSet", "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
뿐만 아니라 {{jsxref("Promise.all", "Promise.all(iterable)")}}, {{jsxref("Promise.race", "Promise.race(iterable)")}}와 {{jsxref("Array.from", "Array.from()")}} 또한 해당된다.
for-of
loops, spread operator, yield*와
destructuring assignment는 iterable과 함께 사용되는 구문(statements)과 표현(expressions)이다.
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(); // { value:"a", done:false } [a, b, c] = new Set(["a", "b", "c"]); a // "a"
만약 Iterable의 @@iterator
메소드가 iterator 객체를 반환하지 않는다면 그것은 잘 정의되지 못한 iterable이라고 할 수 있다. 이러한 iterable을 사용하는 것은 런타임 예외나 예상치 못한 결과를 불러올 수 있다:
var nonWellFormedIterable = {} nonWellFormedIterable[Symbol.iterator] = () => 1 [...nonWellFormedIterable] // TypeError: [] is not a function
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' // ...
generator object 는 iterator 이면서 iterable 입니다.
var aGeneratorObject = function*(){ yield 1; yield 2; yield 3; }(); typeof aGeneratorObject.next; // "function", 이것은 next 메서드를 가지고 있기 때문에 iterator입니다. typeof aGeneratorObject[Symbol.iterator]; // "function", 이것은 @@iterator 메서드를 가지고 있기 때문에 iterable입니다. aGeneratorObject[Symbol.iterator]() === aGeneratorObject; // true, 이 Object의 @@iterator 메서드는 자기자신(iterator)을 리턴하는 것으로 보아 잘 정의된 iterable이라고 할 수 있습니다. [...aGeneratorObject]; // [1, 2, 3]
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|
Basic support | {{CompatChrome(39.0)}} | {{CompatGeckoDesktop("27.0")}} | {{CompatNo}} | 26 | {{CompatNo}} |
IteratorResult object instead of throwing |
{{CompatVersionUnknown}} | {{CompatGeckoDesktop("29.0")}} | {{CompatNo}} | {{CompatVersionUnknown}} | {{CompatNo}} |
Feature | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
Basic support | {{CompatNo}} | {{CompatVersionUnknown}} | {{CompatGeckoMobile("27.0")}} | {{CompatNo}} | {{CompatNo}} | {{CompatNo}} | {{CompatChrome(39.0)}} |
IteratorResult object instead of throwing |
{{CompatNo}} | {{CompatUnknown}} | {{CompatGeckoMobile("29.0")}} | {{CompatNo}} | {{CompatNo}} | {{CompatNo}} | {{CompatVersionUnknown}} |
IteratorResult
object returned instead of throwingStarting with Gecko 29 {{geckoRelease(29)}}, the completed generator function no longer throws a {{jsxref("TypeError")}} "generator has already finished". Instead, it returns an IteratorResult
object like { value: undefined, done: true }
({{bug(958951)}}).
Iterator
property and @@iterator
symbolFrom Gecko 17 (Firefox 17 / Thunderbird 17 / SeaMonkey 2.14) to Gecko 26 (Firefox 26 / Thunderbird 26 / SeaMonkey 2.23 / Firefox OS 1.2) the iterator
property was used (bug 907077), and from Gecko 27 to Gecko 35 the "@@iterator"
placeholder was used. In Gecko 36 (Firefox 36 / Thunderbird 36 / SeaMonkey 2.33), the @@iterator
symbol got implemented (bug 918828).
Specification | Status | Comment |
---|---|---|
{{SpecName('ES6', '#sec-iteration', 'Iteration')}} | {{Spec2('ES6')}} | Initial definition. |
{{SpecName('ESDraft', '#sec-iteration', 'Iteration')}} | {{Spec2('ESDraft')}} |