๋ฐ˜์‘ํ˜•

TL;DR โญ๏ธ


์ดํ„ฐ๋Ÿฌ๋ธ”/์ดํ„ฐ๋ ˆ์ดํ„ฐ ํ”„๋กœํ† ์ฝœ - ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ PoiemaWeb

Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ์ดํ„ฐ๋Ÿฌ๋ธ”(iterable)์ด๋ผ๊ณ  ํ•œ๋‹ค. ๊ฐ„๋‹จํžˆ ๋งํ•˜๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ”์€ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋‹ค. ๋ฐฐ์—ด, ๋ฌธ์ž์—ด์€ Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๋Œ€ํ‘œ์ ์ธ ๋‚ด์žฅ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ๊ฐ์ฒด๋“  โžŠfor of ๋ฐ˜๋ณต๋ฌธ โž‹์ „๊ฐœ ๋ฌธ๋ฒ• โžŒ๋ฐฐ์—ด ๊ตฌ์กฐ๋ถ„ํ•ด ํ• ๋‹น์˜ ๋Œ€์ƒ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

โถ for of ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ผ๊ณ  ํ•œ๋‹ค

 

โท ์ดํ„ฐ๋Ÿฌ๋ธ”์—” Symbol.iterator ๋ฉ”์„œ๋“œ(ํ˜น์€ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ์˜ํ•ด ์ƒ์†)๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

  • Symbol.iterator๋Š” for of์— ์˜ํ•ด ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋˜๋ฉฐ, ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค
  • Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” “์ดํ„ฐ๋ ˆ์ดํ„ฐ”๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค
  • ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋Š” ๋ฐ˜๋ณต ๊ณผ์ •์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, for of ๋ฌธ์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค
  • ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์•ˆ์—๋Š” ๋ฐ˜๋ณต ๋Œ€์ƒ ๊ฐ์ฒด { done: Boolean, value: any } ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” next() ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    • done ์†์„ฑ : ๋ฐ˜๋ณต์˜ ์ข…๋ฃŒ ์—ฌ๋ถ€
    • value ์†์„ฑ : ํ˜„์žฌ ์ˆœํšŒ์ค‘์ธ ์ดํ„ฐ๋Ÿฌ๋ธ”์˜ ๊ฐ’
    • for of ๋ฌธ์—์„œ ๊ฐ’์„ ์ˆœํšŒํ•  ๋•Œ๋งˆ๋‹ค next() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ value๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

 

โธ ๋ฌธ์ž์—ด, ๋ฐฐ์—ด ๊ฐ™์€ ๋‚ด์žฅ ์ดํ„ฐ๋Ÿฌ๋ธ”์—” Symbol.iterator๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ์ด๋“ค์€ ๋ชจ๋‘ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค.

console.log(Symbol.iterator in Array.prototype); // true
console.log(Symbol.iterator in String.prototype); // true
console.log(Symbol.iterator in Object.prototype); // false

 

โน ์œ ์‚ฌ ๋ฐฐ์—ด์€ ์ธ๋ฑ์Šค์™€ length ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง„, ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฐ์ฒด๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ”๊ณผ๋Š” ๋‹ค๋ฅด๋ฏ€๋กœ ์ฃผ์˜.

 

โบ Array.from ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์œ ์‚ฌ ๋ฐฐ์—ด๊ณผ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ง„์งœ ๋ฐฐ์—ด๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

Symbol.iterator — ๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ


๐Ÿ’ก ๋ฐ์ดํ„ฐ ์ปฌ๋ ‰์…˜์„ ์ˆœํšŒํ•˜๊ธฐ ์œ„ํ•ด ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ(๊ทœ์น™)์ด ES6์— ๋„์ž…๋๋‹ค. ์ดํ„ฐ๋ ˆ์ด์…˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ”์€ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜, ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ์˜ํ•ด Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์€ ๊ฐ์ฒด๋ฅผ ๋งํ•œ๋‹ค.

 

์ดํ„ฐ๋Ÿฌ๋ธ”์€ for of ๋ฐ˜๋ณต๋ฌธ / ์ „๊ฐœ ๋ฌธ๋ฒ• / ๋ฐฐ์—ด ๊ตฌ์กฐ๋ถ„ํ•ด ํ• ๋‹น์˜ ๋Œ€์ƒ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฐ์—ด, ๋ฌธ์ž์—ด ๋“ฑ์€ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์†Œ์œ ํ•˜๋ฏ€๋กœ ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋“ค์€ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์ด๋‹ค.

 

์ดํ„ฐ๋Ÿฌ๋ธ”

๋ฐฐ์—ด์€ Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค. Symbol.iterator๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํŠน์ˆ˜ํ•œ ๋‚ด์žฅ ์‹ฌ๋ณผ์ด๋ฉฐ, ํ˜ธ์ถœํ•˜๋ฉด ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋Š” next() ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š”๋‹ค.

 

next()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜์—ฌ value, done ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด(๋ฐ˜๋ณต ๋Œ€์ƒ ๊ฐ์ฒด ํ˜น์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. value ์†์„ฑ์€ ํ˜„์žฌ ์ˆœํšŒํ•˜๋Š” ์š”์†Œ์˜ ๊ฐ’์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

// ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•œ ์˜ˆ์‹œ
const array = [1, 2, 3]; // ๋ฐฐ์—ด์€ ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค
const iterator = array[Symbol.iterator](); // next ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜

// next() ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด๋Š” value์™€ done ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š”๋‹ค
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
iterator.next(); // { value: undefined, done: true }

 

์œ„ ์ฝ”๋“œ์—์„œ โžŠSymbol.iterator ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ → โž‹์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜ → โžŒ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์˜ next() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณผ์ •์€ ์•„๋ž˜ ๋ฐ˜๋ณต๋ฌธ์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

const array = [1, 2, 3];
for (const num of array) {
  console.log(num); // 1, 2, 3
}

 

์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด

์•„๋ž˜ range ๋ณ€์ˆ˜๋Š” ์ˆซ์ž ๊ฐ„๊ฒฉ์„ from(1)๊ณผ to(5) ์†์„ฑ์œผ๋กœ ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐ์ฒด๋‹ค. ์ผ๋ฐ˜ ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด ์•„๋‹ˆ๋ฏ€๋กœ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฆฌ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ•˜์ง€๋งŒ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ(์ดํ„ฐ๋Ÿฌ๋ธ”) ๊ฐ์ฒด๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

const range = { from: 1, to: 5 };

for (const num of range) {
  console.log(num); // Error! range is not iterable
}

 

range ๊ฐ์ฒด์— Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด next() ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ๋œ๋‹ค. for of ๋ฐ˜๋ณต๋ฌธ์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

// ์ฝ”๋“œ ์ฐธ๊ณ  JavaScript Info
// โ‘ด for of ์‹œ์ž‘ ์‹œ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค
range[Symbol.iterator] = function () {
  // โ‘ต Symbol.iterator๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ๋œ๋‹ค
  // for of ๋ฌธ์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค
  return {
    current: this.from,
    last: this.to,

    // โ‘ถ for of ๋ฌธ์„ ์ˆœํšŒํ•  ๋•Œ๋งˆ๋‹ค next() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค
    next() {
      // โ‘ท next()๋Š” { done: Boolean, value: any } ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ๋œ๋‹ค
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
        // current++๋Š” ํ›„์œ„ ์ฆ๊ฐ ์—ฐ์‚ฐ์ž๋ฏ€๋กœ ์ฆ๊ฐ€ํ•˜๊ธฐ ์ „ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์„œ value ์†์„ฑ์— ํ• ๋‹น๋œ๋‹ค
      } else {
        return { done: true };
      }
    },
  };
};

 

๋‹ค์‹œ for of ๋ฌธ์„ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

for (const num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

 

๐Ÿ’ก ์ •๋ฆฌํ•˜๋ฉด Symbol.iterator๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด์™€, ์ด ๊ฐ์ฒด ์•ˆ์— ์ •์˜ํ•œ next() ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ๋ฐ˜๋ณต๋ฌธ์—์„œ ์‚ฌ์šฉํ•  ๊ฐ’์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ตฌ์กฐ๋‹ค.

 

  1. for of ๋ฐ˜๋ณต๋ฌธ ์‹œ์ž‘ → Symbol.iterator ํ˜ธ์ถœ → ๋ฐ˜ํ•œ๋œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘
    1. Symbol.iterator๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค
    2. Symbol.iterator๋Š” ํ•ญ์ƒ next() ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ๋œ๋‹ค. โšก๏ธ
  2. for of ๋ฐ˜๋ณต๋ฌธ์€ ์ˆœํšŒํ•  ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด next() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    1. next() ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’์€ { done: Boolean, value: any } ํ˜•ํƒœ์˜ ๊ฐ์ฒด์—ฌ์•ผ ํ•œ๋‹ค. โšก
    2. done ์†์„ฑ์€ ๋ฐ˜๋ณต์˜ ์ข…๋ฃŒ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
    3. value ์†์„ฑ์€ ํ˜„์žฌ ์ˆœํšŒ์ค‘์ธ ์ดํ„ฐ๋Ÿฌ๋ธ”์˜ ๊ฐ’์ด๋‹ค.

 

๊ฐ์ฒด ์ž์ฒด๋ฅผ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋กœ ๋งŒ๋“ค๊ธฐ

range ๊ฐ์ฒด ์ž์ฒด๋ฅผ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด(range[Symbol.iterator]() ๋ฐ˜ํ™˜๊ฐ’)์™€ ๋ฐ˜๋ณต ๋Œ€์ƒ ๊ฐ์ฒด(next() ๋ฐ˜ํ™˜๊ฐ’)๋ฅผ ํฌํ•จํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋กœ ๋งŒ๋“ค๋ฉด ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

const range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  },
};

 

๐Ÿ’ก range.to์— Infinity๋ฅผ ํ• ๋‹นํ•˜๋ฉด range๋Š” ๋ฌดํ•œ๋Œ€๊ฐ€ ๋œ๋‹ค. ๋งŽ์€ ๋‚œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด์•ผ๋  ๋•Œ ์œ ์šฉ.

  1. for of ๋ฐ˜๋ณต๋ฌธ ์‹œ์ž‘
  2. range[Symbol.iterator]() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  3. range ๊ฐ์ฒด ๋ฐ˜ํ™˜. ์ด ๊ฐ์ฒด์—” ์•„๋ž˜ 2๊ฐœ๋ฅผ ๋ชจ๋‘ ํฌํ•จํ•˜๋ฏ€๋กœ for of ๋ฌธ๋„ ์ž˜ ์ž‘๋™ํ•œ๋‹ค.
    1. ๋ฐ˜๋ณต ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•„์ˆ˜ ๋ฉ”์„œ๋“œ next()
    2. ๋ฐ˜๋ณต ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” this.current

 

๋ช…์‹œ์ ์œผ๋กœ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ํ˜ธ์ถœํ•˜๊ธฐ

๋ฌธ์ž์—ด๋„ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค. ๋”ฐ๋ผ์„œ for of ๋ฌธ์œผ๋กœ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

const str = 'hello';
for (const letter of str) console.log(letter); // h e l l o

 

๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ , ์ด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฌธ์ž์—ด์„ ์ˆœํšŒํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฐ˜๋ณต ์‹œ์ž‘ → ๋ฐ˜๋ณต ์ค‘์ง€ → ๋‹ค๋ฅธ ์ž‘์—… ์ˆ˜ํ–‰ → ๋‹ค์‹œ ๋ฐ˜๋ณต ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ˜๋ณต ๊ณผ์ •์„ ์ชผ๊ฐค ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. 

const str = 'hello';
const iterator = str[Symbol.iterator](); // StringIterator {}

while (true) {
  const { value, done } = iterator.next();
  if (done) break;
  console.log(value); // h e l l o
}

 

์ปค์Šคํ…€ ์ดํ„ฐ๋Ÿฌ๋ธ”๋กœ ํ”ผ๋ณด๋‚˜์น˜ ๊ตฌํ˜„ํ•˜๊ธฐ โญ๏ธ

๐Ÿ’ก ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด ๋“ฑ์€ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ํ™•๋ณดํ•œ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต๊ธ‰ํ•œ๋‹ค. ๋ฐ˜๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์‚ฌ์šฉํ•˜๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ”์ด ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰์ž ์—ญํ• ์„ ํ•˜๋ฉฐ, ์ง€์—ฐ ํ‰๊ฐ€๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ง€์—ฐ ํ‰๊ฐ€๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์‹œ์ ์ด ๋ ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ์ง€์—ฐ ํ‰๊ฐ€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์†Œ๋น„ํ•˜์ง€ ์•Š๊ณ , ๋ฌดํ•œ๋„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

์ผ๋ฐ˜ ๊ฐ์ฒด๋ฅผ ์ดํ„ฐ๋Ÿฌ๋ธ”๋กœ ๋งŒ๋“ค์–ด์„œ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด(1, 2, 3, 5, 8, ...)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

// ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด
const fibonacci = {
  // Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ๋‹ค
  [Symbol.iterator]() {
    let [pre, cur] = [0, 1];
    const max = 10; // ์ตœ๋Œ€๊ฐ’

    // Symbol.iterator ๋ฉ”์„œ๋“œ๋Š” next ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•œ "์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด"๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    return {
      // fibonacci ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•  ๋•Œ๋งˆ๋‹ค next ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค
      // next ๋ฉ”์„œ๋“œ๋Š” "์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด"๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
      next() {
        [pre, cur] = [cur, pre + cur]; // [1, 1] [1, 2] [2, 3] [3, 5] ...
        return {
          value: cur,
          done: cur >= max,
        };
      },
    };
  },
};

// fibonacci ๊ฐ์ฒด๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ” ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ–ˆ์œผ๋ฏ€๋กœ for of ๋ฌธ์œผ๋กœ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ๋‹ค
for (const num of fibonacci) {
  // for of ๋ฌธ์€ done ํ”„๋กœํผํ‹ฐ๊ฐ€ true๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•œ๋‹ค.
  // for of ๋‚ด๋ถ€์—์„œ break ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. *ex) if (num >= 10) break;*
  console.log(num); // 1 2 3 5 8
  // 13๋ถ€ํ„ฐ max ๊ฐ’(10) ์ด์ƒ์ด๋ฏ€๋กœ done ํ”„๋กœํผํ‹ฐ๊ฐ€ true๊ฐ€ ๋ผ์„œ ๋”์ด์ƒ ์ˆœํšŒํ•˜์ง€ ์•Š๋Š”๋‹ค
}

// spread ๋ฌธ๋ฒ•(์ „๊ฐœ์—ฐ์‚ฐ์ž)์„ ์ด์šฉํ•ด ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค
const fiboNum = [...fibonacci]; // [1, 2, 3, 5, 8]

// ์ดํ„ฐ๋Ÿฌ๋ธ”์€ spread ๋ฌธ๋ฒ•, ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น, Map/Set ์ƒ์„ฑ์ž์—๋„ ์‚ฌ์šฉ๋œ๋‹ค
const [first, second, ...rest] = fibonacci; // 1 2 [3, 5, 8]

 

์œ„ ์˜ˆ์ œ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ”์€ ์™ธ๋ถ€์—์„œ ์ตœ๋Œ€ ๋ฐ˜๋ณต ํšŸ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋ฅผ ๊ฐœ์„ ํ•˜๋ ค๋ฉด ์ตœ๋Œ€ ๋ฐ˜๋ณต ํšŸ์ˆ˜์ธ max๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์œผ๋ฏ€๋กœ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค(์ƒ์„ฑํ•œ ๊ฐ์ฒด์— next ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ).

// ์•„๋ž˜ ๊ฐ์ฒด๋Š” Symbol.iterator, next ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ์†Œ์œ ํ–ˆ์œผ๋ฏ€๋กœ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋‹ค
{
  [Symbol.iterator]() { return this; }, // next ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜
  next() { /* ... */ }
}

 

๋”๋ณด๊ธฐ
// ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” fibonacci ํ•จ์ˆ˜
const fibonacci = (max) => {
  let [pre, cur] = [0, 1];

  return {
    // ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์ธ ๊ฐ์ฒด ๋ฐ˜ํ™˜
    [Symbol.iterator]() {
      return this;
    },
    next() {
      [pre, cur] = [cur, pre + cur]; // [1, 1] [1, 2] [2, 3] [3, 5] ...
      return { value: cur, done: cur >= max }; // ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด ๋ฐ˜ํ™˜
    },
  };
};

// iter๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด์„œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ
let iter = fibonacci(10);

// ์—ฌ๊ธฐ์„œ iter๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ
console.log(iter.next()); // {value: 1, done: false}
console.log(iter.next()); // {value: 2, done: false}

iter = fibonacci(20);

// ์—ฌ๊ธฐ์„œ iter๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”
for (const num of iter) console.log(num); // 1 2 3 5 8 13

 

next() ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ๋žตํ•ด์„œ ๋ฌดํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”(๋ฌดํ•œ์˜ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด ์ƒ์„ฑ)์„ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋”๋ณด๊ธฐ
// ๋ฌดํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ƒ์„ฑํ•˜๋Š” fibonacci ํ•จ์ˆ˜
const fibonacci = () => {
  let [pre, cur] = [0, 1];

  return {
    [Symbol.iterator]() {
      return this;
    },
    next() {
      [pre, cur] = [cur, pre + cur]; // [1, 1] [1, 2] [2, 3] [3, 5] ...
      return { value: cur }; // done ํ”„๋กœํผํ‹ฐ ์ƒ๋žต
    },
  };
};

for (const num of fibonacci()) {
  if (num > 1000) break;
  console.log(num); // 1 2 3 5 8 13 ...
}

const [f1, f2, f3] = fibonacci(); // ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น์„ ์ด์šฉํ•ด 3๊ฐœ ์š”์†Œ๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค
console.log(f1, f2, f3); // 1 2 3

 

(๋ฒˆ์™ธ) ES6์—์„œ ์ œ๊ณตํ•˜๋Š” ๋นŒํŠธ์ธ ์ดํ„ฐ๋Ÿฌ๋ธ” ๋ชฉ๋ก

์•„๋ž˜ ํ•ญ๋ชฉ๋“ค์€ ๋ชจ๋‘ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ์†Œ์œ ํ•œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฏ€๋กœ for of ๋ฌธ์œผ๋กœ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋นŒํŠธ์ธ ์ดํ„ฐ๋Ÿฌ๋ธ” 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[Symbol.iterator]
DOM ์ปฌ๋ ‰์…˜ NodeList.prototype[Symbol.iterator]
HTMLCollection.prototype[Symbol.iterator]

 

์ดํ„ฐ๋Ÿฌ๋ธ”๊ณผ ์œ ์‚ฌ ๋ฐฐ์—ด


  • ์ดํ„ฐ๋Ÿฌ๋ธ”(iterable) : Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋œ ๊ฐ์ฒด
  • ์œ ์‚ฌ ๋ฐฐ์—ด(array-like) : ์ธ๋ฑ์Šค์™€ length ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง„, ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฐ์ฒด

 

์•„๋ž˜ arrayLike๋Š” ์ธ๋ฑ์Šค์™€ length ์†์„ฑ์„ ๊ฐ€์ง€๋ฏ€๋กœ ์œ ์‚ฌ ๋ฐฐ์—ด์ด์ง€๋งŒ, ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋Š” ์•„๋‹ˆ๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ for of ๋ฌธ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋ฐ˜๋ฉด ์œ„ ์˜ˆ์‹œ์˜ range ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋Š” length์™€ ์ธ๋ฑ์Šค ์†์„ฑ์ด ์—†์œผ๋ฏ€๋กœ ์œ ์‚ฌ ๋ฐฐ์—ด์ด ์•„๋‹ˆ๋‹ค.

 

๐Ÿ’ก ์˜ˆ์™ธ์ ์œผ๋กœ arguments, NodeList, HTMLCollection์€ ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด๋ฉด์„œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋‹ค.

const arrayLike = {
  0: 'Hello',
  1: 'World',
  length: 2,
};

for (const el of arrayLike) {
} // Error! arrayLike is not iterable
arrayLike.push(2); // arrayLike.push is not a function

 

์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด์™€ ์œ ์‚ฌ ๋ฐฐ์—ด(๊ฐ์ฒด)์€ ๋ฐฐ์—ด์ด ์•„๋‹ˆ๋ฏ€๋กœ push, pop ๊ฐ™์€ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

 

์ดํ„ฐ๋Ÿฌ๋ธ” / ์œ ์‚ฌ๋ฐฐ์—ด์—์„œ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ


Array.from

Array.from ๋ฉ”์„œ๋“œ๋Š” โžŠ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋‚˜ โž‹์œ ์‚ฌ ๋ฐฐ์—ด์„ ๋ฐ›์•„ ์ง„์งœ ๋ฐฐ์—ด(Array)์„ ๋งŒ๋“ ๋‹ค. ๊ทธ๋Ÿผ push ๊ฐ™์€ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Array.from์€ ๋„˜๊ฒจ๋ฐ›์€ ์ธ์ž๊ฐ€ ์ดํ„ฐ๋Ÿฌ๋ธ” ํ˜น์€ ์œ ์‚ฌ ๋ฐฐ์—ด์ด๋ฉด ๊ฐ์ฒด๋‚ด ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ๋ณต์‚ฌํ•œ๋‹ค(์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋ฅผ ๋„˜๊ธฐ๋ฉด next() ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๋ชจ๋“  value ๊ฐ’์ด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์˜ ์š”์†Œ๋กœ ์ถ”๊ฐ€๋œ๋‹ค).

// ์œ ์‚ฌ ๋ฐฐ์—ด
const arrayLike = {
  0: 'Hello',
  1: 'World',
  length: 2,
};

// [์œ ์‚ฌ ๋ฐฐ์—ด -> ๋ฐฐ์—ด]
const arrayFromArrayLike = Array.from(arrayLike); // ['Hello', 'World']
arrayFromArrayLike.push('JavaScript');
console.log(arrayFromArrayLike); // ['Hello', 'World', 'JavaScript']

// [์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด -> ๋ฐฐ์—ด]
// range๋Š” ์œ„ ์˜ˆ์ œ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด
const arrayFromIterable = Array.from(range); // [1, 2, 3, 4, 5]

 

์œ ์‚ฌ ๋ฐฐ์—ด์—์„  length ์†์„ฑ ๊ฐ’ ๋งŒํผ ๋ณต์‚ฌํ•œ ์š”์†Œ๋ฅผ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•œ๋‹ค. ์š”์†Œ ๊ฐœ์ˆ˜๋ณด๋‹ค ๋งŽ์€ length๋ฅผ ์ž…๋ ฅํ–ˆ๋‹ค๋ฉด, length ์œ„์น˜์™€ ๋Œ€์‘ํ•˜๋Š” ์š”์†Œ๊ฐ€ ์—†์„๋• undefined๊ฐ€ ๋ฐฐ์—ด์— ๋‹ด๊ธฐ๋ฏ€๋กœ ์ฃผ์˜ํ•œ๋‹ค.

 

๐Ÿ’ก Array.from ์ฒซ๋ฒˆ์งธ ์ธ์ž์— ํŠน์ • ๊ธธ์ด๋ฅผ ๊ฐ–๋Š” ๋ฐฐ์—ด์„ ๋„˜๊ธธ ๋•Œ Array(n) ๋Œ€์‹  { length: n } ํ˜•ํƒœ๋กœ ๋„˜๊ธธ ์ˆ˜๋„ ์žˆ๋‹คex) Array.from({ length: 2 })[undefined, undefined]

const arrayLike = {
  0: 'Hello',
  1: 'World',
  length: 4,
};

Array.from(arrayLike); // ['Hello', 'World', undefined, undefined]

 

Array.from ๋งคํ•‘ ํ•จ์ˆ˜

Array.from(arrayLike[, mapFn[, thisArg]])

 

Array.from ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” ๋งคํ•‘ ํ•จ์ˆ˜๋ฅผ ๋ฐ›๋Š”๋‹ค. ๋งคํ•‘ ํ•จ์ˆ˜๋ฅผ ๋„˜๊ธฐ๋ฉด ๊ฐ์ฒด์˜ ๊ฐ ์š”์†Œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•ด๋‹น ๋งคํ•‘ ํ•จ์ˆ˜๊ฐ€ ์ ์šฉ๋œ ๊ฐ’์ด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ๋‹ด๊ธด๋‹ค. thisArg๋Š” ๊ฐ ์š”์†Œ์— this๋ฅผ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

// range๋Š” ์œ„ ์˜ˆ์ œ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด
Array.from(range); // ๋งคํ•‘ ํ•จ์ˆ˜ ์ ์šฉ ์ „ [1, 2, 3, 4, 5]
Array.from(range, num => num * 2); // ๋งคํ•‘ ํ•จ์ˆ˜ ์ ์šฉ ํ›„ [2, 4, 6, 8, 10]

 

Array.from์€ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง„ ์ดํ„ฐ๋Ÿฌ๋ธ” ์†์„ฑ์„ ์ด์šฉํ•ด ๋™์ž‘ํ•˜๋ฉฐ, ๋‚ด๋ถ€์—์„  ์•„๋ž˜์™€ ๋™์ผํ•œ ๋ฐ˜๋ณต๋ฌธ์ด ๋Œ์•„๊ฐ„๋‹ค.

// Array.from ๋‚ด๋ถ€๋Š” ์•„๋ž˜์™€ ๋™์ผํ•œ ๋ฐ˜๋ณต๋ฌธ์ด ์ž‘๋™ํ•œ๋‹ค
const arr = [];
for (const num of range) {
  arr.push(num);
}

console.log(arr); // [1, 2, 3, 4, 5]

 

Array.from๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ” ์†์„ฑ์„ ์ด์šฉํ•ด ๋™์ž‘ํ•˜๋ฏ€๋กœ ๋ฌธ์ž์—ด์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const str = 'hello';
Array.from(str); // ['h', 'e', 'l', 'l', 'o']
[...str]; // ['h', 'e', 'l', 'l', 'o'] -> ์ „๊ฐœ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค

 

for of / for in ๋‚ด๋ถ€ ๋™์ž‘์˜ ์ฐจ์ด์  โญ๏ธ


for of์™€ for in ๋ฌธ์€ ์œ ์‚ฌํ•ด๋ณด์ด์ง€๋งŒ ๋‚ด๋ถ€๋Š” ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

 

for of

for of ๋ฌธ์€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์˜ next ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ดํ„ฐ๋Ÿฌ๋ธ”(Symbol.iterator ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๊ฐ์ฒด)์„ ์ˆœํšŒํ•œ๋‹ค. next ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ value ํ”„๋กœํผํ‹ฐ ๊ฐ’์€ for of ๋ฌธ์˜ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ๋‹ค. ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด์˜ done ์†์„ฑ์ด false๋ฉด ๋ฐ˜๋ณต์„ ๊ณ„์†ํ•˜๊ณ , true๋ฉด ๋ฐ˜๋ณต์„ ์ค‘์ง€ํ•œ๋‹ค.

for (๋ณ€์ˆ˜์„ ์–ธ๋ฌธ of ์ดํ„ฐ๋Ÿฌ๋ธ”) {
  /* ... */
}

 

for in

for in ๋ฌธ์€ ๊ฐ์ฒด์˜ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ํ”„๋กœํ† ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ ์ค‘์—์„œ ํ”„๋กœํผํ‹ฐ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ(ํ”Œ๋ž˜๊ทธ) [[Enumerable]] ๊ฐ’์ด true์ธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ์—ด๊ฑฐ(enumeration) ํ•œ๋‹ค(๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ ํ˜น์€ ์ƒ์†๋ฐ›์€ ํ”„๋กœํ† ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ). ํ”„๋กœํผํ‹ฐ ํ‚ค๊ฐ€ ์‹ฌ๋ฒŒ์ธ ํ”„๋กœํผํ‹ฐ๋Š” ์—ด๊ฑฐํ•˜์ง€ ์•Š๋Š”๋‹ค.

for (๋ณ€์ˆ˜์„ ์–ธ๋ฌธ in ๊ฐ์ฒด) {
  /* ... */
}

 

ํ”„๋กœํผํ‹ฐ์˜ ์—ด๊ฑฐ ๊ฐ€๋Šฅ์—ฌ๋ถ€๋Š” ํ”„๋กœํผํ‹ฐ ์„ค๋ช…์ž ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Object.getOwnPropertyDescriptor ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ ์„ค๋ช…์ž์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋งํฌ ์ฐธ๊ณ .

const obj = { name: 'John' };
Object.getOwnPropertyDescriptor(obj, 'name');
// {value: 'John', writable: true, enumerable: true, configurable: true}
// enumerable ํ”Œ๋ž˜๊ทธ๊ฐ€ true์ด๋ฏ€๋กœ for in ๋ฌธ์œผ๋กœ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

 

for in์€ ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒ์† ๋ฐ›์€ ํ”„๋กœํ† ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๊นŒ์ง€ ์—ด๊ฑฐํ•œ๋‹ค. ํ•˜์ง€๋งŒ toString ๊ฐ™์€ Object.prototype์˜ ํ”„๋กœํผํ‹ฐ๋Š” [[Enumerable]] ๊ฐ’์ด false ์ด๋ฏ€๋กœ ์—ด๊ฑฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

Object.getOwnPropertyDescriptor(Object.prototype, 'toString');
// {writable: true, enumerable: false, configurable: true, value: ƒ}

for (const attr in Object.prototype) console.log(attr); // undefined

 

Symbol.asyncIterator — ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ


์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋Š” ๋ชจ๋‘ ๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋‹ค. ๋งŒ์•ฝ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋งŒ๋“œ๋ ค๋ฉด ์•„๋ž˜ ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค.

 

  1. Symbol.iterator ๋Œ€์‹  Symbol.asyncIterator ์‚ฌ์šฉ
  2. next ๋ฉ”์„œ๋“œ๋Š” ํ”„๋กœ๋ฏธ์Šค ๋ฐ˜ํ™˜
  3. ๋ฐ˜๋ณต ์ž‘์—…์€ for await (const item of iterable) ์‚ฌ์šฉ

 

  ๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ
์ดํ„ฐ๋ ˆ์ดํ„ฐ ์ œ๊ณต ๋ฉ”์„œ๋“œ Symbol.iterator Symbol.asyncIterator
next() ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜ ๊ฐ’ ๋ชจ๋“  ๊ฐ’ Promise
๋ฐ˜๋ณต ์ž‘์—… for of for await of
const range = {
  from: 1,
  to: 5,
  // ๋ฐ˜๋ณต๋ฌธ ์ตœ์ดˆ ์‹คํ–‰ ์‹œ Symbol.asyncIterator ํ˜ธ์ถœ -> ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด ๋ฐ˜ํ™˜
  [Symbol.asyncIterator]() {
    return {
      current: this.from,
      last: this.to,
      // next ๋ฉ”์„œ๋“œ ์•ž์— async ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์˜€์œผ๋ฏ€๋กœ ํ•ญ์ƒ ํ”„๋กœ๋ฏธ์Šค ๋ฐ˜ํ™˜
      // ๋ฐ˜๋ณต๋ฌธ์— ์˜ํ•ด ๊ฐ ์ดํ„ฐ๋ ˆ์ด์…˜๋งˆ๋‹ค next() ํ˜ธ์ถœ -> ํ”„๋กœ๋ฏธ์Šค๋กœ ๊ฐ์‹ผ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฆฌ์ ˆํŠธ ๊ฐ์ฒด ๋ฐ˜ํ™˜
      async next() {
        await new Promise((resolve) => setTimeout(resolve, 1000)); // ๋น„๋™๊ธฐ ์ž‘์—…

        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        }
        return { done: true };
      },
    };
  },
};

(async () => {
  for await (const value of range) console.log(value);
})(); // 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ 1~5๊นŒ์ง€ ์ถœ๋ ฅ

 

๐Ÿ’ก ์ „๊ฐœ ๋ฌธ๋ฒ•์€ ์ผ๋ฐ˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ(Symbol.iterator)๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์—์„  ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

console.log(...range); // Found non-callable @@iterator

 

๋ ˆํผ๋Ÿฐ์Šค


 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”
๋ฐ˜์‘ํ˜•