dev.syw

Symbol, 이터러블 프로토콜, for...of, 제너레이터 function* 를 다룬다.

이터레이터·제너레이터·심볼

for...of 가 어떻게 배열을 순회하는지 궁금했다면, 그 비밀은 이터레이터에 있습니다. 이번 레슨에서는 Symbol, 이터러블 프로토콜, 제너레이터까지 언어의 깊은 곳을 들여다봅니다.

학습 목표

  • Symbol 의 용도와 특성을 이해한다
  • 이터러블 프로토콜의 동작을 설명할 수 있다
  • for...of 로 다양한 자료구조를 순회할 수 있다
  • 제너레이터 function*yield 를 사용할 수 있다
  • 제너레이터를 실무에 활용할 수 있다

Symbol

Symbol유일무이한 값을 만드는 원시 타입입니다. 같은 설명을 주어도 절대 같지 않습니다.

const a = Symbol('id');
const b = Symbol('id');
console.log(a === b); // → false (항상 고유)

// 객체 키로 쓰면 충돌·중복이 없는 "숨은" 속성이 됨
const ID = Symbol('id');
const user = { name: '민수', [ID]: 1001 };
console.log(user[ID]); // → 1001
JavaScript

💡 TIP — Symbol 키는 일반 순회(for...in, Object.keys)에 나타나지 않아 메타데이터를 숨기는 데 쓰입니다. 또 Symbol.iterator 같은 "잘 알려진 심볼"이 언어 동작을 정의합니다.

이터러블 프로토콜

객체가 Symbol.iterator 메서드를 가지면 이터러블이 되어 for...of·스프레드·구조 분해의 대상이 됩니다. 그 메서드는 next() 를 가진 이터레이터를 돌려줍니다.

const range = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    let current = this.from;
    const last = this.to;
    return {
      next() {
        return current <= last
          ? { value: current++, done: false }
          : { value: undefined, done: true };
      },
    };
  },
};

console.log([...range]); // → [1, 2, 3]
for (const n of range) console.log(n); // → 1, 2, 3
JavaScript

next(){ value, done } 형태를 돌려주며, done: true 가 되면 순회가 끝납니다.

for...of

이터러블이라면 무엇이든 for...of 로 순회합니다.

for (const ch of '가나다') console.log(ch); // → 가, 나, 다
for (const x of new Set([1, 2, 2])) console.log(x); // → 1, 2
for (const [k, v] of new Map([['a', 1]])) console.log(k, v); // → a 1
JavaScript

⚠️ 주의 — 일반 객체({})는 이터러블이 아니라 for...of 로 돌 수 없습니다. 키-값 순회는 Object.entries(obj) 로 이터러블을 얻으세요.

제너레이터 — function*

제너레이터는 이터레이터를 간단히 만드는 함수입니다. function* 로 선언하고 yield 로 값을 하나씩 내보냅니다.

function* count() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = count();
console.log(gen.next()); // → { value: 1, done: false }
console.log(gen.next()); // → { value: 2, done: false }
console.log([...count()]); // → [1, 2, 3]
JavaScript

함수는 yield 에서 멈췄다가 다음 next() 호출 때 이어서 실행됩니다.

function* range(from, to) {
  for (let i = from; i <= to; i++) {
    yield i;
  }
}
console.log([...range(1, 5)]); // → [1, 2, 3, 4, 5]
JavaScript

앞의 range 객체를 제너레이터로 다시 쓰면 훨씬 짧아집니다.

const iterable = {
  from: 1,
  to: 3,
  *[Symbol.iterator]() {
    for (let i = this.from; i <= this.to; i++) yield i;
  },
};
console.log([...iterable]); // → [1, 2, 3]
JavaScript

활용 — 무한 시퀀스와 ID 생성기

제너레이터는 필요할 때마다 값을 계산하므로 무한 수열도 다룰 수 있습니다.

function* idMaker() {
  let id = 1;
  while (true) {
    yield id++;
  }
}

const next = idMaker();
console.log(next.next().value); // → 1
console.log(next.next().value); // → 2
JavaScript

💡 TIP — 제너레이터는 메모리에 모든 값을 담지 않고 요청 시점에 하나씩 만들어내므로(지연 평가), 큰 데이터나 무한 시퀀스에 적합합니다.

요약

  • Symbol 은 고유한 값으로, 충돌 없는 객체 키와 언어 동작 정의에 쓰인다
  • Symbol.iterator 메서드를 가지면 이터러블이 되어 for...of·스프레드가 가능하다
  • 이터레이터의 next(){ value, done } 을 돌려준다
  • 제너레이터 function*yield 로 이터레이터를 간단히 만든다
  • 제너레이터는 지연 평가로 무한 시퀀스와 큰 데이터를 효율적으로 다룬다

연습문제

  1. Symbol 두 개를 만들고 같은 설명이어도 다르다는 것을 비교로 확인하세요.
  2. 1부터 n까지 짝수만 내보내는 제너레이터 evens(n) 을 작성하세요.

    힌트for 안에서 if (i % 2 === 0) yield i;

  3. 객체에 [Symbol.iterator] 를 구현해 for...of 로 순회 가능하게 만드세요.
  4. 호출할 때마다 1씩 증가하는 ID 를 돌려주는 무한 제너레이터를 작성하고 3번 호출해 보세요.

    힌트while (true) yield id++;

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

JavaScript” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.