[JavaScript] generator

빵호·2022년 1월 11일
0

JavaScript

목록 보기
25/28
post-thumbnail

generator

제너레이터(generator)는 함수의 실행을 중간에 멈추고 재개할 수 있는 기능이다. 실행을 멈출 때 값을 전달할 수 있기 때문에 반복문에서 제너레이터가 전달하는 값을 하나씩 꺼내서 사용할 수 있고 이는 배열이 반복문에서 사용되는 방식과 같다. 값을 미리 만들어 놓지 않고 필요한 순간에 값을 계산해서 전달할 수 있기 때문에 메모리 측면에서 효율적이다.

사용법

제너레이터는 별표와 함께 정의된 함수와 그 함수가 반환하는 제너레이터 객체로 구성되고 next, return, throw 메서드를 가지고 있다.

function* f1() { // 1
  yield 10; // 2
  yield 20;
  return 'finisihed'
}
const gen = f1(); // 3
console.log(gen.next()); // 4
// { value: 10, done: false }
console.log(gen.next());
// { value: 20, done: false }
console.log(gen.next()); // 5
// { value: 'finisihed', done: true }
console.log(gen.next()); // 6 
// { value: undefined, done: true }
  1. 함수에 별표를 함께 사용해 제너레이터 함수를 생성한다.
  2. yield 키워드를 사용해 함수의 실행을 멈춘다.
  3. 제너레이터 함수를 실행하면 제너레이터 객체가 반환되는데 실제 내부 코드는 실행되지 않는다.
  4. 반환되는 데이터 객체는 { value: 10, done: false } 이다. yield 키워드 오른쪽 값이 데이터 객체의 value 속성값으로 넘어온다.
  5. 반환되는 데이터 객체는 { value: 'finisihed', done: true } 이다. yield 키워드를 만나지 못하면 done 속성값은 true가 되고 return 값이 value 속성값으로 넘어온다.
  6. 반환되는 데이터 객체는 { value: undefined, done: true } 이다. 이후 next 메서드를 호출해도 done 속성값은 true가 된다.
function* f1() { 
  try { // 1
  yield 10; 
  yield 20;
  } cathc (e) {
    console.log('catch', e);
  }
}
const get = f1();
console.log(gen.next());
// { value: 10, done: false }
console.log(get.throw('some error')); // 2
// catch some error
// { value: undefined, done: true }
}
  1. try catch 문을 사용해서 예외 처리를 한다.
  2. throw 메서드를 호출하면 예외가 발생한 것으로 처리되어 catch 문으로 들어가고 데이터 객체의 done 값은 true가 된다.

반복자

제너레이터 객체는 반복 가능하면서 반복자이다.

  1. next 메서드를 갖고 있다.
  2. next 메서드는 value와 done 속성값을 가진 객체를 반환한다.
  3. done 속성값은 작업이 끝났을 때 참이 된다.

위 조건을 만족하는 객체는 반복자이다.

  1. Symbol.iterator 속성값으로 함수를 가지고 있다.
  2. 해당 함수를 호출하면 반복자를 반환한다.

위 조건을 만족하는 객체는 반복 가능(iterable)한 객체이다.

const arr = [10, 20, 30];
const iter = arr[Symbol.iterator](); 
console.log(iter.next()); // { value: 10, done: false }

Symbol.iterator 속성값을 함수로 갖고 있고 함수가 반환한 iter 변수도 반복자이기 때문에 배열은 반복 가능한 객체다.

function* f1() {
  yield 10;
  yield 20;
  yield 30;
}

const gen = f1();
console.log(Symbol.iterator]() === gen); // true

for (const v of f1()) { // 1
  console.log(v);
}
// 10 
// 20 
// 30
const arr = [...f1()]; // 2
console.log(arr); // [ 10, 20, 30 ];

Symbol.iterator 속성값을 호출한 결과가 자기 자신(반복자)이다. 따라서 제너레이터 객체는 반복 가능한 객체이고 반복 가능한 객체는 for of 문, 전개 연산자에서 유용하게 쓰인다.

  1. for of 문은 반복 가능한 객체로부터 반복자를 얻고 done 속성값이 true가 될 때까지 next 메서드를 호출한다.
  2. 전개 연산자도 done 속성값이 true가 될 때까지 값을 펼친다.

제너레이터 함수끼리 호출

function* g1() {
  yield 2;
  yield 3;
}
function* g2() {
  yield 1;
  yield* g1(); 
  yield 4;
}
console.log(...g2()); // 1 2 3 4

제너레이터 함수에서 다른 제너레이터 함수를 호출할 때는 yield* 키워드를 이용한다.

제너레이터 함수로 데이터 전달

function* f1() {
  const data1 = yield; 3️⃣
  console.log(data1); // 10
  const data2 = yield; 3️⃣
  console.log(data2); // 20
}
const gen = f1();
gen.next(); 1️⃣
gen.next(10); 2️⃣
gen.next(20); 2️⃣
  1. 첫 번째 next 메서드 호출은 제너레이터 함수의 실행이 시작하도록 하는 역할
  2. next 메서드의 인수로 데이터 전달
  3. next 메서드로 전달된 인수를 yield의 결과값으로 사용
profile
늘 한결같이 꾸준히

0개의 댓글