๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Lang
JavaScript
17-iterators and generators

1. ์ดํ„ฐ๋Ÿฌ๋ธ”(iterable)

์ดํ„ฐ๋ ˆ์ด์…˜์„ JS์—์„œ๋Š” ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ(Iteration Protocol)์ด๋ผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

  • ์ดํ„ฐ๋ ˆ์ด์…˜(iteration)๋Š” โ€œ๋ฐ˜๋ณต, ์ˆœํšŒโ€๋ผ๋Š” ๋œป์ž…๋‹ˆ๋‹ค.
  • ํ”„๋กœํ† ์ฝœ์€ โ€œ๊ทœ๊ฒฉ, ์•ฝ์†, ์ธํ„ฐํŽ˜์ด์Šคโ€์™€ ๋™์ผํ•œ ๋ง์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅธ๋‹ค๋Š” ๊ฒƒ์€ โ€œ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹คโ€๋ผ๊ณ ๋„ ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JS์—์„œ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ๊ฐ์ฒด๋Š” for...of, spread ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ด๋“ค์€ ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.

์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ๊ธฐ๋ณธ JS ์ž๋ฃŒ ๊ตฌ์กฐ๋Š” Array, String, Map, Set์œผ๋กœ ์ด๋“ค์€ ๋ชจ๋‘ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— for...of, spread ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ํ”„๋กœํ† ์ฝœ(๊ทœ๊ฒฉ)์„ ์ค€์ˆ˜ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ฌด์Šจ ์˜๋ฏธ์ผ๊นŒ์š”? ๊ทœ๊ฒฉ์„ ๋”ฐ๋ฅธ๋‹ค๋Š” ๊ฒƒ์€ ์–ด๋–ค ๊ฐ์ฒด๋“ ์ง€ ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฒซ ๋ฒˆ์งธ๋กœ๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ๋Š” ํ”„๋กœํ† ์ฝœ ๋Œ€์‹ ์— ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋Š” ๋ง์„ ๋” ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ˆœํšŒํ•˜๊ณ  ์‹ถ์€ ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๊ฐ€ ๋˜๋ ค๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋ฉด ๋˜๋Š”๋ฐ, ๊ทธ ์–ด๋–ค ๊ฐ์ฒด ์•ˆ์—์„œ๋„ symbo.iterater๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ, ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๋งŒ ํ•˜๋ฉด, ์„ ์–ธํ•œ ๊ฐ์ฒด๋Š” โ€œ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋‹ค. ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ๊ฐ์ฒด๋‹ค.โ€๋ผ๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
{
2
[Symbol.iterator]() : iterator ํ”„๋กœํ† ์ฝœ {
3
next(): ๋‹ค์Œ๊ฐ’
4
}
5
}

์ฆ‰, ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋˜๋ ค๋ฉด ๋‚ด ์˜ค๋ธŒ์ ํŠธ ์•ˆ์— symbo.iterater๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ํ•จ์ˆ˜์—์„œ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ์ˆœํšŒํ•˜๋Š” ๋ฐ˜๋ณต์ž๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ๊ทœ๊ฒฉ ์‚ฌํ•ญ๋งŒ ๋”ฐ๋ฅด๋ฉด, for...of, spread ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

JavaScript์—์„œ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด 2๊ฐ€์ง€ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ผ์•ผ ํ•œ๋‹ค.
    • ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅธ๋‹ค๋Š” ๋ง์€ Symbol.iterator๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๋Š” ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•ด์•ผ ํ•จ
  2. ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํ”„๋กœํ† ์ฝœ์€ next๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ์–ด์„œ ๋‹ค์Œ ๊ฐ’์„ ๊ณ„์† ๋ฆฌํ„ดํ•˜๋„๋ก ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

cf. MDN iteration protocols


1.1 ์˜ˆ์ œ 1

1
// Iterable ํ•˜๋‹ค๋Š”๊ฑด? ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค!
2
// [Symbol.iterator](): IterableIterator<T>;
3
// ์‹ฌ๋ณผ์ •์˜๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋‚˜, ํŠน์ •ํ•œ ํ•จ์ˆ˜๊ฐ€ IterableIterator<T>๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ๊ฒƒ์€
4
// ์ˆœํšŒ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋‹ค! ๋ผ๋Š”๊ฒƒ์„ ์˜๋ฏธ
5
// ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋‚˜? for..of, spread ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ๊ฐ€๋Šฅ
6
const array = [1, 2, 3];
7
8
// ๐Ÿ“ for...of ์—ฐ์‚ฐ์ž : ๋ฐฐ์—ด ์•ˆ์— ์žˆ๋Š” ์•„์ดํ…œ์„ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ€์ ธ์˜ด
9
for (let item of array) {
10
console.log(item); // 1, 2, 3
11
}
12
13
// for...in : key๋ฅผ ์ถœ๋ ฅ
14
const obj = { 0: 1, 1: 2 };
15
for (let item in obj) {
16
console.log(item); // obj์•ˆ์— ์žˆ๋Š” key๋ฅผ ์ถœ๋ ฅ

1.2 ์˜ˆ์ œ 2

1
// Iterable ํ•˜๋‹ค๋Š”๊ฑด? ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค!
2
// [Symbol.iterator](): IterableIterator<T>;
3
// ์‹ฌ๋ณผ์ •์˜๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋‚˜, ํŠน์ •ํ•œ ํ•จ์ˆ˜๊ฐ€ IterableIterator<T>๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ๊ฒƒ์€
4
// ์ˆœํšŒ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋‹ค! ๋ผ๋Š”๊ฒƒ์„ ์˜๋ฏธ
5
// ์ˆœํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋‚˜? for..of, spread ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ๊ฐ€๋Šฅ
6
const array = [1, 2, 3]
7
8
// ๐Ÿ“ for...of ์—ฐ์‚ฐ์ž : ๋ฐฐ์—ด ์•ˆ์— ์žˆ๋Š” ์•„์ดํ…œ์„ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ€์ ธ์˜ด
9
// ๐Ÿ“ array.entries() : [ํ‚ค, ๊ฐ’] ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ
10
for (const item of array.entries()) {
11
console.log(item)
12
/*
13
[ 0, 1 ]
14
[ 1, 2 ]
15
[ 2, 3 ]
16
*/
17
}
18
19
// for...in : key๋ฅผ ์ถœ๋ ฅ
20
const obj = { 0: 1, 1: 2 }
21
for (const item in obj) {
22
console.log(item) // obj์•ˆ์— ์žˆ๋Š” key๋ฅผ ์ถœ๋ ฅ -> 0, 1
23
}
24
25
const iterator = array.values()
26
27
// done์€ ๋ฐ˜๋ณต์ด ๋๋‚˜๋ฉด true, ์•ˆ๋๋‚˜๋ฉด false
28
// console.log(iterator.next()); // { value: 1, done: false }
29
while (true) {
30
const item = iterator.next()
31
if (item.done) break
32
console.log(item.value)
33
}
34
35
// console.log(iterator.next().value); // 1
36
// console.log(iterator.next().value); // 2
37
// console.log(iterator.next().value); // 3
38
// console.log(iterator.next().done); // true
39
40
// for (let item of iterator) {
41
// console.log(item); // 1, 2, 3
42
// }

1.3 ์˜ˆ์ œ 3

1
// [Symbol.iterator](): IterableIterator<T>;
2
// 0๋ถ€ํ„ฐ 10์ดํ•˜๊นŒ์ง€ ์ˆซ์ž์˜ 2๋ฐฐ๋ฅผ ์ˆœํšŒํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ(๋ฐ˜๋ณต์ž) ๋งŒ๋“ค๊ธฐ!
3
// 0, 1, 2, 3, ..., 9
4
// 0, 2, 4, 6, ..., 18
5
6
const multiple = {
7
// [Symbol.iterator] ํ•จ์ˆ˜
8
[Symbol.iterator]: () => {
9
const max = 10
10
let num = 0
11
// ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋ฐ˜ํ™˜๋จ
12
return {
13
// next ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผ ํ•จ
14
next() {
15
// 10 ์ดˆ๊ณผ๋˜๋ฉด done์ด true๊ฐ€ ๋˜์–ด ์ˆœํ™˜์ด ์ •์ง€
16
return { value: num++ * 2, done: num > max }
17
},
18
}
19
},
20
}
21
22
console.clear()
23
for (const num of multiple) {
24
console.log(num)
25
}

2. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ(Generator)

์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๋ฐ”๊พผ ๊ฒƒ์ด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ(Generator)์ž…๋‹ˆ๋‹ค. Generator๋„ ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜์ง€๋งŒ, ์กฐ๊ธˆ ๋” ๊ฐ„ํŽธํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
// ๐Ÿ“ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ(์ƒ์„ฑ๊ธฐ) : ๊ฐ’์„ ์ƒ์„ฑ
2
// function๋‹ค์Œ์— *๋ฅผ ๋ถ™์ด๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋กœ ์ธ์‹
3
function* multipleGenerator() {
4
try {
5
for (let i = 0; i < 10; i++) {
6
console.log(i) // 0๊นŒ์ง€๋งŒ ์ถœ๋ ฅ
7
// return : ๋ฐ”๋กœ ๊ฐ’์„ ๋ฆฌํ„ด
8
yield i ** 2 // yield : ์‚ฌ์šฉ์ž๊ฐ€ next๋ฅผ ํ˜ธ์ถœํ•  ๋–„๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•˜๋‚˜์”ฉ ๋ฆฌํ„ด
9
// ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ์–ด๊ถŒ์„ ์–‘๋„ = yield
10
}
11
} catch (error) {
12
console.log(error)
13
}
14
}
15
const multiple = multipleGenerator()
16
let next = multiple.next()
17
console.log(next.value, next.done) // 0 false
18
19
// multiple.return();
20
multiple.throw('Error!') // Error!
21
22
next = multiple.next()
23
console.log(next.value, next.done) // undefined true