MDN wants to talk to developers like you: https://qsurvey.mozilla.com/s3/8d22564490d8

반복기 및 생성기

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

자세한 내용은, 다음을 참조하세요:

반복기

객체는 한 번에 하나씩 컬렉션 항목을 액세스하는 법을 아는 경우 반복기(iterator)입니다, 그 열(sequence) 내부 현재 위치를 기억하면서. JavaScript에서 반복기는 열 내 다음 항목을 반환하는 next() 메서드를 제공하는 객체입니다. 이 메서드는 다음 두 속성이 있는 객체를 반환합니다: donevalue.

일단 생성되면, 반복기 객체는 명시해서 next()를 반복 호출하여 사용될 수 있습니다.

function makeIterator(array){
    var nextIndex = 0;

    return {
       next: function(){
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    }
}

일단 초기화되면, next() 메서드는 차례로 객체에서 키-값 쌍에 액세스하기 위해 호출될 수 있습니다:

var it = makeIterator(['yo', 'ya']);
console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done);  // true

iterable

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

반복가능하기 위해서, 객체는 @@iterator 메서드를 구현해야 합니다, 객체(나 그 프로토타입 체인에 등장하는 객체 중 하나)가 Symbol.iterator 키를 갖는 속성이 있어야 함을 뜻하는:

사용자 정의 iterable

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

var myIterable = {}
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable] // [1, 2, 3]

내장 iterable

String, Array, TypedArray, MapSet은 모두 내장 반복가능 객체입니다, 그들의 프로토타입 객체가 모두 Symbol.iterator 메서드가 있기에.

iterable을 기대하는 구문

일부 문(statement) 및 식(expression)은 iterable을 기대합니다, 가령 for-of 루프, 전개 연산자, yield*해체 할당.

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"

생성기

사용자 정의 반복기는 유용한 도구이지만, 반복기 생성은 명시적으로 그들의 내부 상태를 유지할 필요 때문에 주의깊은 프로그래밍이 필요합니다. 생성기는 강력한 대안을 제공합니다: 자신의 상태를 유지할 수 있는 단일 함수를 작성하여 반복 알고리즘을 정의할 수 있게 합니다.

생성기는 반복기 팩토리로서 작동하는 특별한 유형의 함수입니다. 함수가 하나 이상의 yield 식을 포함하고 function* 구문을 사용하면 생성기가 됩니다.

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
// ...

고급 생성기

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

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

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

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
주의: 흥미롭게도, next(undefined) 호출은 next() 호출과 같습니다. 그러나, next() 호출할 때 undefined 이외의 값으로 신생 생성기를 시작하면 TypeError 예외가 발생합니다.

throw() 메서드를 호출하며 발생해야 할 예외 값을 전달하여 예외를 발생하도록 생성기를 강제할 수 있습니다. 이 예외는 생성기의 현재 중단된 문맥에서 발생됩니다, 마치 현재 중단된 yieldthrow value 문 대신인 것처럼.

발생한 예외 처리 도중 yield를 만나지 않는 경우, 그 뒤 예외는 throw() 호출을 통해 위로 전하며 next()의 후속 호출 결과 done 속성은 true가 됩니다.

생성기는 주어진 값을 반환하고 생성기 자체를 끝내는 return(value) 메서드가 있습니다.

문서 태그 및 공헌자

 이 페이지의 공헌자: Netaras
 최종 변경: Netaras,