aboutsummaryrefslogtreecommitdiff
path: root/files/ko/web/javascript/guide/iterators_and_generators/index.html
blob: 72164c82743426a554d0e447d32be47fbb59b157 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
---
title: 반복기 및 생성기
slug: Web/JavaScript/Guide/Iterators_and_Generators
tags:
  - Guide
  - Intermediate
  - JavaScript
translation_of: Web/JavaScript/Guide/Iterators_and_Generators
---
<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</div>

<p >컬렉션 내 각 항목 처리는 매우 흔한 연산입니다. JavaScript는 간단한 {{jsxref("Statements/for","for")}} 루프에서 {{jsxref("Global_Objects/Array/map","map()")}}{{jsxref("Global_Objects/Array/filter","filter()")}}에 이르기까지, 컬렉션을 반복하는 많은 방법을 제공합니다. 반복기(iterator) 및 생성기(generator)는 반복 개념을 핵심 언어 내로 바로 가져와 {{jsxref("Statements/for...of","for...of")}} 루프의 동작(behavior)을 사용자 정의하는 메커니즘을 제공합니다.</p>

<p>자세한 내용은, 다음을 참조하세요:</p>

<ul>
 <li><a href="/ko/docs/Web/JavaScript/Reference/Iteration_protocols">반복 프로토콜</a></li>
 <li>{{jsxref("Statements/for...of","for...of")}}</li>
 <li>{{jsxref("Statements/function*","function*")}}{{jsxref("Generator")}}</li>
 <li>{{jsxref("Operators/yield","yield")}}{{jsxref("Operators/yield*","yield*")}}</li>
</ul>

<h2 id="반복자">반복자</h2>

<p>자바스크립트에서 <strong>반복자(Iterator)</strong>는 시퀀스를 정의하고  종료시의 반환값을 잠재적으로 정의하는 객체입니다.  더 구체적으로 말하자면, 반복자는 두 개의 속성( <code>value</code>, <code>done</code>)을 반환하는 next() 메소드 사용하여  객체의 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">Iterator protocol</a>을 구현합니다. 시퀀스의 마지막 값이 이미 산출되었다면 <code>done</code> 값은 true 가 됩니다. 만약 <code>value</code>값이 <code>done</code> 과 함께 존재한다면, 그것은 반복자의 반환값이 됩니다.</p>

<p>반복자를 생성하면 <code>next()</code> 메소드를 반복적으로 호출하여 명시적으로 반복시킬 수 있습니다.  반복자를 반복시키는 것은 일반적으로 한 번씩만 할 수 있기 때문에, 반복자를 소모시키는 것이라고 할 수 있습니다. 마지막 값을 산출하고나서  <code>next()</code>를 추가적으로 호출하면 <code>{done: true}</code>. 가 반환됩니다.</p>

<p>자바스크립트에서 가장 일반적인 반복자는 배열 반복자로, 배열의 각 값을 순서대로 반환합니다. 모든 반복자가 배열로 표현될수 있다고 상상할 수 있지만 , 이것은 사실은 아닙니다. 배열은 완전히 할당되어야 하지만,  반복자는 필요한만큼만 소모되므로  무제한 시퀀스로 표현할 수 있습니다. 이를 테면 0부터 무한대사이의 정수범위처럼 말이죠.</p>

<p>여기에 실습할 수 있는 예제가 있습니다.  <code>start</code>에서 <code>end</code>까지 <code>step</code> 수 만큼 띄어진  정수 시퀀스를 정의하는 간단한 범위 반복자를 만들 수 있습니다. 최종적으로 시퀀스의 크기가 반환됩니다.</p>

<pre><code>function makeRangeIterator(start = 0, end = Infinity, step = 1) {
    var nextIndex = start;
    var n = 0;

    var rangeIterator = {
       next: function() {
           var result;
           if (nextIndex &lt; end) {
               result = { value: nextIndex, done: false }
           } else if (nextIndex == end) {
               result = { value: n, done: true }
           } else {
               result = { done: true };
           }
           nextIndex += step;
           n++;
           return result;
       }
    };
    return rangeIterator;
}</code>
</pre>

<p>위의 반복자를 사용하면 아래와 같습니다:</p>

<pre><code>var it = makeRangeIterator(1, 4);

var result = it.next();
while (!result.done) {
 console.log(result.value); // 1 2 3
 result = it.next();
}

console.log("Iterated over sequence of size: ", result.value);</code>
</pre>

<div class="note">
<p>It is not possible to know reflectively whether a particular object is an iterator. If you need to do this, use <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Iterators_and_Generators$edit#Iterables">Iterables</a>.</p>
</div>

<h2 id="Generator_functions">Generator functions</h2>

<p>잘 만들어진 반복자(Iterator)는 유용한 도구인 반면, 이것을 생성할 때는 주의해서 프로그래밍을 해야 하는데, 반복자 내부에 명시적으로 상태를 유지할 필요가 있기 때문입니다. 생성자(Generator) 함수는 이에 대한 강력한 대안을 제공합니다: 실행이 연속적이지 않은 하나의 함수를 작성함으로서 개발자가 iterative algorithm을 정의할 수 있게 해줍니다. 생성자 함수는 {{jsxref("Statements/function*","function*")}} 문법을 사용하여 작성됩니다. 생성자 함수가 최초로 호출될 때, 함수 내부의 어떠한 코드도 실행되지 않고, 대신 생성자라고 불리는 반복자 타입을 반환합니다. 생성자의 <strong>next</strong> 메소드를 호출함으로서 어떤 값이 소비되면, 생성자 함수는 <strong>yield</strong> 키워드를 만날 때까지 실행됩니다. </p>

<p>생성자 함수는 원하는 만큼 호출될 수 있고, 매번 새로운 생성자를 반환합니다다. 하지만, 각 생성자는 단 한 번만 순회될 수 있을 것입니다.</p>

<p>위의 예제 코드에 생성자를 적용한 것입니다. 두 코드의 행위는 동일하지만, 생성자를 사용한 쪽이 쓰거나 읽기가 훨씬 쉽습니다. </p>

<pre><code>function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
    let n = 0;
    for (let i = start; i &lt; end; i += step) {
        n++;
        yield i;
    }
    return n;
}</code></pre>

<h2 id="Iterables">Iterables</h2>

<p>객체는 값이 {{jsxref("Statements/for...of", "for..of")}} 구조 내에서 반복되는 것 같은 그 반복 동작을 정의하는 경우 반복이 가능(<strong>iterable</strong>)합니다. {{jsxref("Array")}} 또는 {{jsxref("Map")}}과 같은 일부 내장 형은 기본 반복 동작이 있지만 다른 형(가령 {{jsxref("Object")}})은 없습니다.</p>

<p><strong>반복가능</strong>하기 위해서, 객체는 <strong>@@iterator</strong> 메서드를 구현해야 합니다. 즉, 객체( 혹은 그 <a href="/ko/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain" title="prototype chain">프로토타입 체인</a>에 등장하는 객체 중 하나)가 {{jsxref("Symbol.iterator")}} 키를 갖는 속성이 있어야 함을 뜻합니다.</p>

<p>하나의 iterable은 단 한 번, 혹은 여러번 반복가능합니다. 어떤 순간에 어떻게 사용할 지는 프로그래머에게 달려있습니다. 단 한 번 반복가능한 iterable(e.g. Generator)은 관습적으로 자신의 <strong>@@iterator</strong> 메소드로부터 <strong>this</strong>를 반환합니다. 반면, 여러 번 반복 가능한 iterables은 <strong>@@iterator </strong>메소드가 호출되는 매 회 새로운 iterator를 반드시 반환해야합니다. </p>

<h3 id="사용자_정의_iterable">사용자 정의 iterable</h3>

<p>이와 같이 자신의 반복가능 객체를 만들 수 있습니다:</p>

<pre><code>var myIterable = {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
    }
}

for (let value of myIterable) {
    console.log(value);
}
// 1
// 2
// 3

or

[...myIterable]; // [1, 2, 3]</code></pre>

<h3 id="내장_iterable">내장 iterable</h3>

<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}}{{jsxref("Set")}}은 모두 내장 반복가능 객체입니다, 그들의 프로토타입 객체가 모두 {{jsxref("Symbol.iterator")}} 메서드가 있기 때문입니다.</p>

<h3 id="iterable을_기대하는_구문">iterable을 기대하는 구문</h3>

<p>일부 문(statement) 및 식(expression)은 iterable합니다, 가령 {{jsxref("Statements/for...of","for-of")}} 루프, {{jsxref("Operators/Spread_operator","spread syntax","","true")}}, {{jsxref("Operators/yield*","yield*")}}{{jsxref("Operators/Destructuring_assignment","해체 할당","","true")}}.</p>

<pre class="brush: js">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"


</pre>

<h2 id="Generator_심화">Generator 심화</h2>

<p> 생성자 함수는 요청에 따라 그 산출된(yielded, yield 식으로 산출된) 값을 계산하고, 계산하기 비싼(힘든) 수열 또는 위에 설명한 대로 무한 수열이라도 효율적으로 나타내게 합니다.</p>

<p>{{jsxref("Global_Objects/Generator/next","next()")}} 메서드는 또한 생성기의 내부 상태를 수정하는 데 쓰일 수 있는 값을 받습니다. <code>next()</code>에 전달되는 값은 생성기가 중단된 마지막 <code>yield</code> 식의 결과로 처리됩니다.</p>

<p>여기 sequence(수열)을 재시작하기 위해 <code>next(x)</code>를 사용하는 피보나치 생성기가 있습니다:</p>

<pre class="brush: js">function* fibonacci(){
  var fn1 = 0;
  var fn2 = 1;
  while (true){
    var current = fn1;
    fn1 = fn2;
    fn2 = current + fn1;
    var reset = yield current;
    if (reset){
        fn1 = 0;
        fn2 = 1;
    }
  }
}

var sequence = fibonacci();
console.log(sequence.next().value);     // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2
console.log(sequence.next().value);     // 3
console.log(sequence.next().value);     // 5
console.log(sequence.next().value);     // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2
</pre>

<p>You can force a generator to throw an exception by calling its {{jsxref("Global_Objects/Generator/throw","throw()")}} method and passing the exception value it should throw. This exception will be thrown from the current suspended context of the generator, as if the <code>yield</code> that is currently suspended were instead a <code>throw<em>value</em></code> statement.</p>

<p>If the exception is not caught from within the generator,  it will propagate up through the call to <code>throw()</code>, and subsequent calls to <code>next()</code> will result in the <code>done</code> property being <code>true</code>.</p>

<p>Generators have a {{jsxref("Global_Objects/Generator/return","return(value)")}} method that returns the given value and finishes the generator itself.</p>

<p>{{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</p>