ν‹°μŠ€ν† λ¦¬ λ·°

μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œ(iteration protocol)

ES6μ—μ„œ λ„μž…λœ μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ€ 순회 κ°€λŠ₯ν•œ 데이터 μ»¬λ ‰μ…˜(자료ꡬ쑰)을 λ§Œλ“€κΈ° μœ„ν•΄ ECMAScript 사양에 μ •μ˜ν•˜μ—¬ 미리 μ•½μ†ν•œ κ·œμΉ™μž…λ‹ˆλ‹€.

  • ES6 μ΄μ „μ˜ 순회 κ°€λŠ₯ν•œ 데이터 μ»¬λ ‰μ…˜(λ°°μ—΄, λ¬Έμžμ—΄, μœ μ‚¬ λ°°μ—΄ 객체, DOM μ»¬λ ‰μ…˜ λ“±)은 ν†΅μΌλœ κ·œμ•½ 없이 각자 λ‚˜λ¦„μ˜ ꡬ쑰λ₯Ό 가지고 for λ¬Έ, for ... in λ¬Έ, forEach λ©”μ„œλ“œ λ“± λ‹€μ–‘ν•œ λ°©λ²•μœΌλ‘œ μˆœνšŒν•  수 μžˆμ—ˆμŒ
  • ES6μ—μ„œ 순회 κ°€λŠ₯ν•œ 데이터 μ»¬λ ‰μ…˜μ„ μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ” μ΄ν„°λŸ¬λΈ”λ‘œ ν†΅μΌν•˜μ—¬ for ... of λ¬Έ, μŠ€ν”„λ ˆλ“œ 문법, λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήμ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ„λ‘ 일원화

μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ—μ„œλŠ” μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œκ³Ό μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œμ΄ μžˆμŠ΅λ‹ˆλ‹€.

 

μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œ

  • Well-Known Symbol인 Symbol.iteratorλ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•œ λ©”μ„œλ“œλ₯Ό 직접 κ΅¬ν˜„ν•˜κ±°λ‚˜ ν”„λ‘œν† νƒ€μž… 체인을 톡해 상속받은 Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ μ΄ν„°λ ˆμ΄ν„°λ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” κ·œμ•½
  • μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ 객체λ₯Ό μ΄ν„°λŸ¬λΈ”μ΄λΌ 함
  • μ΄ν„°λŸ¬λΈ”μ€ for ... of 문으둜 μˆœνšŒν•  수 있으며 μŠ€ν”„λ ˆλ“œ 문법과 λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήμ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš© κ°€λŠ₯

μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œ

  • μ΄ν„°λ ˆμ΄ν„°λŠ” next λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•˜λ©° next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λŸ¬λΈ”μ„ μˆœνšŒν•˜λ©° value와 done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” κ·œμ•½
  • μ΄ν„°λŸ¬λΈ”μ˜ Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ μ΄ν„°λ ˆμ΄ν„°λ₯Ό λ°˜ν™˜
  • μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ 객체λ₯Ό μ΄ν„°λ ˆμ΄ν„°λΌ 함
  • μ΄ν„°λ ˆμ΄ν„°λŠ” μš”μ†Œλ₯Ό νƒμƒ‰ν•˜κΈ° μœ„ν•œ 포인터 역할을 함

 

μ΄ν„°λŸ¬λΈ”

μ΄ν„°λŸ¬λΈ”μ€ Symbol.iteratorλ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•œ λ©”μ„œλ“œλ₯Ό 직접 κ΅¬ν˜„ν•˜κ±°λ‚˜ ν”„λ‘œν† νƒ€μž… 체인을 톡해 상속받은 객체둜 μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ 객체λ₯Ό λ§ν•©λ‹ˆλ‹€.

 

μ΄ν„°λŸ¬λΈ”μΈμ§€ ν™•μΈν•˜λŠ” ν•¨μˆ˜λŠ” λ‹€μŒκ³Ό 같이 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

const isIterable = v => v !== null && typeof v[Symbol.iterator] === 'function';

// λ°°μ—΄, λ¬Έμžμ—΄, Map, Set 등은 μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
isIterable([]);        // -> true
isIterable('');        // -> true
isIterable(new Map()); // -> true
isIterable(new Set()); // -> true
isIterable({});        // -> false

 

μ΄ν„°λŸ¬λΈ”μ€ for ... of 문으둜 μˆœνšŒν•  수 있으며, μŠ€ν”„λ ˆλ“œ 문법과 λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήμ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

const array = [1, 2, 3];

// 배열은 Array.prototype의 Symbol.iterator λ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ” μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
console.log(Symbol.iterator in array); // true

// μ΄ν„°λŸ¬λΈ”μΈ 배열은 for...of 문으둜 순회 κ°€λŠ₯ν•˜λ‹€.
for (const item of array) {
  console.log(item);
}

// μ΄ν„°λŸ¬λΈ”μΈ 배열은 μŠ€ν”„λ ˆλ“œ λ¬Έλ²•μ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.
console.log([...array]); // [1, 2, 3]

// μ΄ν„°λŸ¬λΈ”μΈ 배열은 λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήμ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.
const [a, ...rest] = array;
console.log(a, rest); // 1, [2, 3]

 

이처럼 배열은 Array.prototype의 Symbol.iterator λ©”μ„œλ“œλ₯Ό μƒμ†λ°›λŠ” μ΄ν„°λŸ¬λΈ”μž…λ‹ˆλ‹€.

 

*일반 κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ μ΄ν„°λŸ¬λΈ”μ΄ μ•„λ‹ˆλ―€λ‘œ for ... of 문으둜 μˆœνšŒν•  수 μ—†μœΌλ©°, μŠ€ν”„λ ˆλ“œ 문법과 λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήμ˜ λŒ€μƒμœΌλ‘œ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. (μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λ©΄ μ΄ν„°λŸ¬λΈ”λ‘œ λ§Œλ“€ 수 있음)

 

일반 κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ”μ΄ μ•„λ‹ˆμ§€λ§Œ, TC39 ν”„λ‘œμ„ΈμŠ€μ˜ stage 4(Finished) 단계에 μ œμ•ˆλ˜μ–΄ μžˆλŠ” μŠ€ν”„λ ˆλ“œ ν”„λ‘œνΌν‹° μ œμ•ˆμ€ 일반 객체에 μŠ€νŠΈλ ˆλ“œ λ¬Έλ²•μ˜ μ‚¬μš©μ„ ν—ˆμš©ν•©λ‹ˆλ‹€.

 

const obj = { a: 1, b: 2 };

// μŠ€ν”„λ ˆλ“œ ν”„λ‘œνΌν‹° μ œμ•ˆ(Stage 4)은 객체 λ¦¬ν„°λŸ΄ λ‚΄λΆ€μ—μ„œ μŠ€ν”„λ ˆλ“œ λ¬Έλ²•μ˜ μ‚¬μš©μ„ ν—ˆμš©ν•œλ‹€.
console.log({ ...obj }); // { a: 1, b: 2 }

 

μ΄ν„°λ ˆμ΄ν„°

μ΄ν„°λ ˆμ΄ν„°λŠ” μ΄ν„°λ ˆμ΄ν„° ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ 객체둜 μ΄ν„°λŸ¬λΈ”μ˜ Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ λ°˜ν™˜λ©λ‹ˆλ‹€.

 

// 배열은 μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
const array = [1, 2, 3];

// Symbol.iterator λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„°λ₯Ό λ°˜ν™˜ν•œλ‹€.
const iterator = array[Symbol.iterator]();

// Symbol.iterator λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„°λŠ” next λ©”μ„œλ“œλ₯Ό κ°–λŠ”λ‹€.
console.log('next' in iterator); // true

 

μ΄ν„°λ ˆμ΄ν„°λŠ” next λ©”μ„œλ“œλ₯Ό 가지고 μžˆμ–΄ μ΄ν„°λŸ¬λΈ”μ˜ 각 μš”μ†Œλ₯Ό μˆœνšŒν•˜κΈ° μœ„ν•œ ν¬μΈν„°μ˜ 역할을 ν•©λ‹ˆλ‹€. 즉, next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λŸ¬λΈ”μ„ 순차적으둜 ν•œ 단계씩 μˆœνšŒν•˜λ©° 순회 κ²½κ³Όλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 ꡬ성은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • value ν”„λ‘œνΌν‹° : ν˜„μž¬ 순회 쀑인 μ΄ν„°λŸ¬λΈ”μ˜ κ°’
  • done ν”„λ‘œνΌν‹° : μ΄ν„°λŸ¬λΈ”μ˜ 순회 μ™„λ£Œ μ—¬λΆ€
// 배열은 μ΄ν„°λŸ¬λΈ” ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.
const array = [1, 2, 3];

// Symbol.iterator λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„°λ₯Ό λ°˜ν™˜ν•œλ‹€. μ΄ν„°λ ˆμ΄ν„°λŠ” next λ©”μ„œλ“œλ₯Ό κ°–λŠ”λ‹€.
const iterator = array[Symbol.iterator]();

// next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ΄ν„°λŸ¬λΈ”μ„ μˆœνšŒν•˜λ©° 순회 κ²°κ³Όλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό
// λ°˜ν™˜ν•œλ‹€. μ΄ν„°λ ˆμ΄ν„° 리절트 κ°μ²΄λŠ” value와 done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” 객체닀.
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

빌트인 μ΄ν„°λŸ¬λΈ”

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œ 객체인 빌트인 μ΄ν„°λŸ¬λΈ”μ„ μ œκ³΅ν•©λ‹ˆλ‹€.

 

빌트인 μ΄ν„°λŸ¬λΈ” Symbol.iterator λ©”μ„œλ“œ
Array Array.prototype[Symbol.iterator]
String String.prototype[Symbol.iterator]
Map Map.prototype[Symbol.iterator]
Set Set.prototype[Symbol.iterator]
TypedArray TypedArray.prototype[Symbol.iterator]
arguments arguments.prototype[Symbol.iterator]
DOM μ»¬λ ‰μ…˜ NodeList.prototype[Symbol.iterator]
HTMLCollection.prototype[Symbol.iterator]

for ... of λ¬Έ

for ... of 문은 μ΄ν„°λŸ¬λΈ”μ„ μˆœνšŒν•˜λ©΄μ„œ μ΄ν„°λŸ¬λΈ”μ˜ μš”μ†Œλ₯Ό λ³€μˆ˜μ— ν• λ‹Ήν•©λ‹ˆλ‹€.

 

for (λ³€μˆ˜μ„ μ–Έλ¬Έ of μ΄ν„°λŸ¬λΈ”) { ... }

 

for ... of 문은 λ‚΄λΆ€μ μœΌλ‘œ μ΄ν„°λ ˆμ΄ν„°μ˜ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ΄ν„°λŸ¬λΈ”μ„ μˆœνšŒν•˜λ©° next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹° 값을 for ... of 문의 λ³€μˆ˜μ— ν• λ‹Ήν•©λ‹ˆλ‹€. μ΄λ•Œ, μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 done ν”„λ‘œνΌν‹° 값이 true이면 μ΄ν„°λŸ¬λΈ”μ˜ 순회λ₯Ό μ€‘λ‹¨ν•©λ‹ˆλ‹€.

 

for (const item of [1, 2, 3]) {
  // item λ³€μˆ˜μ— 순차적으둜 1, 2, 3이 ν• λ‹Ήλœλ‹€.
  console.log(item); // 1 2 3
}


// for ... of 문의 λ‚΄λΆ€λ™μž‘μ„ for 문으둜 ν‘œν˜„
// μ΄ν„°λŸ¬λΈ”
const iterable = [1, 2, 3];

// μ΄ν„°λŸ¬λΈ”μ˜ Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ΄ν„°λ ˆμ΄ν„°λ₯Ό μƒμ„±ν•œλ‹€.
const iterator = iterable[Symbol.iterator]();

for (;;) {
  // μ΄ν„°λ ˆμ΄ν„°μ˜ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ΄ν„°λŸ¬λΈ”μ„ μˆœνšŒν•œλ‹€. μ΄λ•Œ next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
  const res = iterator.next();

  // next λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 done ν”„λ‘œνΌν‹° 값이 true이면 μ΄ν„°λŸ¬λΈ”μ˜ 순회λ₯Ό μ€‘λ‹¨ν•œλ‹€.
  if (res.done) break;

  // μ΄ν„°λ ˆμ΄ν„° 리절트 객체의 value ν”„λ‘œνΌν‹° 값을 item λ³€μˆ˜μ— ν• λ‹Ήν•œλ‹€.
  const item = res.value;
  console.log(item); // 1 2 3
}

 

*for ... in λ¬Έκ³Ό μœ μ‚¬ν•˜μ§€λ§Œ, for ... in 문은 μ‹¬λ²ŒμΈ ν”„λ‘œνΌν‹° ν‚€λ₯Ό μ—΄κ±°ν•˜μ§€ μ•ŠμŒ


μ΄ν„°λŸ¬λΈ”κ³Ό μœ μ‚¬ λ°°μ—΄ 객체

μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” 마치 λ°°μ—΄μ²˜λŸΌ 인덱슀둜 ν”„λ‘œνΌν‹° 값에 μ ‘κ·Όν•  수 있고 length ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” 객체λ₯Ό λ§ν•©λ‹ˆλ‹€.

  • length ν”„λ‘œνΌν‹°λ₯Ό κ°–κΈ° λ•Œλ¬Έμ— for 문으둜 순회 κ°€λŠ₯
  • 인덱슀λ₯Ό λ‚˜νƒ€λ‚΄λŠ” 숫자 ν˜•μ‹μ˜ λ¬Έμžμ—΄μ„ ν”„λ‘œνΌν‹° ν‚€λ‘œ κ°€μ§€λ―€λ‘œ λ°°μ—΄μ²˜λŸΌ 인덱슀둜 ν”„λ‘œνΌν‹° 값에 μ ‘κ·Ό κ°€λŠ₯

ν•˜μ§€λ§Œ, μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ”μ΄ μ•„λ‹Œ 일반 객체라 Symbol.iterator λ©”μ„œλ“œκ°€ μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ for ... of 문으둜 μˆœνšŒν•  수 μ—†μŠ΅λ‹ˆλ‹€.

 

*단, μ˜ˆμ™Έμ μœΌλ‘œ ES6μ—μ„œ μ΄ν„°λŸ¬λΈ”μ΄ λ„μž…λ˜λ©° μœ μ‚¬ λ°°μ—΄ 객체인 arguments, NodeList, HTMLCollection 와 배열에 Symbol.iterator λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ΄ν„°λŸ¬λΈ”μ΄ λ˜μ—ˆμŒ

 

// μœ μ‚¬ λ°°μ—΄ 객체
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

// μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” length ν”„λ‘œνΌν‹°λ₯Ό κ°–κΈ° λ•Œλ¬Έμ— for 문으둜 μˆœνšŒν•  수 μžˆλ‹€.
for (let i = 0; i < arrayLike.length; i++) {
  // μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” 마치 λ°°μ—΄μ²˜λŸΌ 인덱슀둜 ν”„λ‘œνΌν‹° 값에 μ ‘κ·Όν•  수 μžˆλ‹€.
  console.log(arrayLike[i]); // 1 2 3

// μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” μ΄ν„°λŸ¬λΈ”μ΄ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— for...of 문으둜 μˆœνšŒν•  수 μ—†λ‹€.
for (const item of arrayLike) {
  console.log(item); // 1 2 3
}
// -> TypeError: arrayLike is not iterable

// μœ μ‚¬ λ°°μ—΄ 객체
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

// Array.from은 μœ μ‚¬ λ°°μ—΄ 객체 λ˜λŠ” μ΄ν„°λŸ¬λΈ”μ„ λ°°μ—΄λ‘œ λ³€ν™˜ν•œλ‹€
const arr = Array.from(arrayLike);
console.log(arr); // [1, 2, 3]

 

ν•˜μ§€λ§Œ μœ„ 예제처럼 μœ μ‚¬ λ°°μ—΄ 객체에 ES6μ—μ„œ λ„μž…λœ Array.from λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ°°μ—΄λ‘œ κ°„λ‹¨νžˆ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ˜ ν•„μš”μ„±

μ΄ν„°λŸ¬λΈ”μ€ for ... of λ¬Έ, μŠ€ν”„λ ˆλ“œ 문법, λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ ν• λ‹Ήκ³Ό 같은 데이터 μ†ŒλΉ„μžμ— μ˜ν•΄ μ‚¬μš©λ˜λ―€λ‘œ 데이터 κ³΅κΈ‰μžμ˜ 역할을 ν•œλ‹€κ³  ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ, λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μžκ°€ μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ„λ‘ κ·œμ •ν•˜λ©΄ 데이터 μ†ŒλΉ„μžλŠ” μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† λ³Όλ§Œ μ§€μ›ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λ©΄ λ©λ‹ˆλ‹€.

 

* λ§Œμ•½, ES6 이전 λ°©μ‹μ²˜λŸΌ ν†΅μΌλœ κ·œμ•½ 없이 λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μžκ°€ 각자의 순회 방식을 가진닀면 μ†ŒλΉ„μžλ„ λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μžμ˜ 순회 방식을 λͺ¨λ‘ 지원해야 ν•΄μ„œ λΉ„νš¨μœ¨μ μž„

 

 

이처럼 μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ€ λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μžκ°€ ν•˜λ‚˜μ˜ 순회 방식을 갖도둝 κ·œμ •ν•˜μ—¬ 데이터 μ†ŒλΉ„μžκ°€ 효율적으둜 λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μžλ₯Ό μ‚¬μš©ν•  수 μžˆλ„λ‘ "데이터 μ†ŒλΉ„μžμ™€ 데이터 κ³΅κΈ‰μžλ₯Ό μ—°κ²°ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ˜ μ—­ν• "을 ν•©λ‹ˆλ‹€.


μ‚¬μš©μž μ •μ˜ μ΄ν„°λŸ¬λΈ”

μ‚¬μš©μž μ •μ˜ μ΄ν„°λŸ¬λΈ” κ΅¬ν˜„

μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜μ§€ μ•ŠλŠ” 일반 객체도 μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λ©΄ μ‚¬μš©μž μ •μ˜ μ΄ν„°λŸ¬λΈ”μ΄ λ©λ‹ˆλ‹€. 

 

// μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ μ΄ν„°λ ˆμ΄ν„°μΈ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];

  // Symbol.iterator λ©”μ„œλ“œμ™€ next λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•œ μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ μ΄ν„°λ ˆμ΄ν„°μΈ 객체λ₯Ό λ°˜ν™˜
  return {
    [Symbol.iterator]() { return this; },
    // next λ©”μ„œλ“œλŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
    next() {
      [pre, cur] = [cur, pre + cur];
      return { value: cur, done: cur >= max };
    }
  };
};

// iterλŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ μ΄ν„°λ ˆμ΄ν„°λ‹€.
let iter = fibonacciFunc(10);

// iterλŠ” μ΄ν„°λŸ¬λΈ”μ΄λ―€λ‘œ for...of 문으둜 μˆœνšŒν•  수 μžˆλ‹€.
for (const num of iter) {
  console.log(num); // 1 2 3 5 8
}

// iterλŠ” μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ μ΄ν„°λ ˆμ΄ν„°λ‹€
iter = fibonacciFunc(10);

// iterλŠ” μ΄ν„°λ ˆμ΄ν„°μ΄λ―€λ‘œ μ΄ν„°λ ˆμ΄μ…˜ 리절트 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” next λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•œλ‹€.
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 2, done: false }
console.log(iter.next()); // { value: 3, done: false }
console.log(iter.next()); // { value: 5, done: false }
console.log(iter.next()); // { value: 8, done: false }
console.log(iter.next()); // { value: 13, done: true }
  • Symbol.iterator λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³  ν•΄λ‹Ή λ©”μ„œλ“œκ°€ next λ©”μ„œλ“œλ₯Ό κ°–λŠ” μ΄ν„°λ ˆμ΄ν„°λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 함
  • μ΄ν„°λ ˆμ΄ν„°μ˜ next λ©”μ„œλ“œλŠ” done κ³Ό value ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§€λŠ” μ΄ν„°λ ˆμ΄ν„° 리절트 객체λ₯Ό λ°˜ν™˜
  • for ... of λ¬Έ, μŠ€ν”„λ ˆλ“œ 문법, λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ 할당에 μ‚¬μš© κ°€λŠ₯
  • fibonacciFunc은 μ΄ν„°λŸ¬λΈ”μ΄λ©΄μ„œ μ΄ν„°λ ˆμ΄ν„°μΈ 객체λ₯Ό μƒμ„±ν•˜λŠ” ν•¨μˆ˜

 

λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”κ³Ό 지연 평가

λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜μ—¬ λ¬΄ν•œ μˆ˜μ—΄μ€ κ°„λ‹¨ν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

// λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•˜λŠ” ν•¨μˆ˜
const fibonacciFunc = function () {
  let [pre, cur] = [0, 1];

  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      // λ¬΄ν•œμ„ κ΅¬ν˜„ν•΄μ•Ό ν•˜λ―€λ‘œ done ν”„λ‘œνΌν‹°λ₯Ό μƒλž΅ν•œλ‹€.
      return { value: cur };
    }
  };
};

// fibonacciFunc ν•¨μˆ˜λŠ” λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ„ μƒμ„±ν•œλ‹€.
for (const num of fibonacciFunc()) {
  if (num > 10000) break;
  console.log(num); // 1 2 3 5 8...4181 6765
}

// λ°°μ—΄ λ””μŠ€νŠΈλŸ­μ²˜λ§ 할당을 톡해 λ¬΄ν•œ μ΄ν„°λŸ¬λΈ”μ—μ„œ 3개의 μš”μ†Œλ§Œ μ·¨λ“ν•œλ‹€.
const [f1, f2, f3] = fibonacciFunc();
console.log(f1, f2, f3); // 1 2 3

 

μœ„ 예제의 μ΄ν„°λŸ¬λΈ”μ€ 지연 평가λ₯Ό 톡해 데이터λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

  • 데이터가 ν•„μš”ν•œ μ‹œμ  μ΄μ „κΉŒμ§€λŠ” 미리 데이터λ₯Ό μƒμ„±ν•˜μ§€ μ•Šλ‹€κ°€ 데이터가 ν•„μš”ν•œ μ‹œμ μ΄ 되면 데이터λ₯Ό 생성
  • 평가 κ²°κ³Όκ°€ ν•„μš”ν•  λ•ŒκΉŒμ§€ 평가λ₯Ό λŠ¦μΆ”λŠ” 기법

 

이처럼 지연 평가λ₯Ό μ‚¬μš©ν•˜λ©΄ λΆˆν•„μš”ν•œ 데이터λ₯Ό 미리 μƒμ„±ν•˜μ§€ μ•Šκ³  ν•„μš”ν•œ 데이터λ₯Ό ν•„μš”ν•œ μˆœκ°„μ— μƒμ„±ν•˜λ―€λ‘œ λΉ λ₯Έ μ‹€ν–‰ 속도λ₯Ό κΈ°λŒ€ν•  수 있고 λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬λ₯Ό μ†ŒλΉ„ν•˜μ§€ μ•ŠμœΌλ©΄ λ¬΄ν•œλ„ ν‘œν˜„ν•  수 μžˆλ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.


[좜처] λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive

https://wikibook.co.kr/mjs/

 

λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive: μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리

269개의 κ·Έλ¦Όκ³Ό 원리λ₯Ό νŒŒν—€μΉ˜λŠ” μ„€λͺ…μœΌλ‘œ ‘μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리’λ₯Ό μ΄ν•΄ν•˜μž! μ›ΉνŽ˜μ΄μ§€μ˜ λ‹¨μˆœν•œ 보쑰 κΈ°λŠ₯을 μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ μ œν•œμ μΈ μš©λ„λ‘œ νƒœμ–΄λ‚œ μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 과도

wikibook.co.kr