on your mark

[JAVASCRIPT.INFO] 5.6 iterable 객체 본문

WEB/Javascript

[JAVASCRIPT.INFO] 5.6 iterable 객체

dev-olive 2023. 1. 9. 22:11

5.6 iterable 객체

반복 가능한(iterable, 이터러블) 객체는 배열을 일반화한 객체이다. 이터러블이라는 개념을 사용하면 어떤 객체에든 for..of반복문을 적용할 수 있다.

배열이 아닌 객체가 있는데, 이 객체가 어떤 것들의 컬렉션(목록, 집합)을 나타내고 있는 경우, for..of문법을 적용할 수만 있다면 컬렉션을 순회하는데 유용할 것이다.

Symbol.iterator

let range = {
  from: 1,
  to: 5
}

range를 이터러블로 만들려면 (for..of가 동작하도록 하려면) 객체에 Symbol.iterator라는 메서드를 추가해 다음과 같은 일이 벌어지도록 해야 한다.

  1. for..of가 시작되자마자 for..ofSymbol.iterator를 호출한다. (Symbol.iterator가 없으면 에러 발생) Symbol.iterator는 반드시 이터레이터(메서드next 가 있는 객체)를 반환해야 한다.
  2. 이후 for..of반환된 객체(이터레이터)만을 대상으로 동작한다.
  3. for..of에 다음 값이 필요하면, for..of는 이터레이터의 next()메서드를 호출한다.
  4. next()의 반환 값은 {done: Boolean, value: any}와 같은 형태이어야 한다. done=true는 반복이 종료되었음을 의미한다. done=false일 땐 value에 다음 값이 저장된다.
let range = {
  from: 1,
  to: 5
}
// 1. for .. of 최초 호출 시, Symbol.iterator가 호출된다.
range[Symbol.iterator] = function(){
  // Symbol.iterator는 이터레이터 객체를 반환
  // 2. 이후 for .. of 는 반환된 이터레이터 객체만을 대상으로 동작하는데, 이 때 다음 값도 정해짐
  return {
    current: this.from,
    last: this.to,

    // 3. for .. of 반복문에 의해 반복마다 next()가 호출됨
    next() {
        // 4. next()는 값을 객체 {done: .., value: ...} 형태로 반환해야 함  
      if(this.current <= this.last){
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    }
  }
};

for(let num of range){
  console.log(num);         // 1, 2, 3, 4, 5
}
let range = {
  from: 1,
  to: 5,

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

  next() {
    if(this.current<= this.to) {
      return {done: false, value: this.current ++};
    } else {
      return {done: true};
    }
  }
};
for(let num of range){
  console.log(num); // 1,2,3,4,5
}

문자열은 이터러블

배열과 문자열은 가장 광범위하게 쓰이는 내장 이터러블이다.

for(let char of "test") {
  alert(char);    // t, e, s, t
}
let str = '𝒳😂';
for(let char of str){
  alert(char);        //𝒳, 😂
}

이터레이터를 명시적으로 출력

let str = "Hello";
let iterator = str[Symbol.iterator]();
while(true){
  let result = iterator.next();
  if(result.done) break;
  alert(result.value);        // 하나씩 출력
}

이 방법을 사용하면 반복 과정을 더 잘 통제 할 수 있다는 장점이 있다.

이터러블과 유사 배열

  • 이터러블Symbol.iterator가 구현된 객치를 의미
  • 유사배열은 인덱스와 length 프로퍼티가 있어서 배열처럼 보이는 객체

이터러블과 유사배열은 대개 배열이 아니기 때문에 push, pop 등의 메서드를 지원하지 않는다.

Array.from

Array.from은 이터러블이나 유사 배열을 받아 진짜 Array를 만들어준다. 이 과정을 거치면 이터러블이나 유사 배열에 배열 메서드를 사용할 수 있다.

let arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
}
let arr = Array.from(arrayLike);
alert(arr.pop());        // World
let arr = Array.from(range);
alert(arr);        // 1,2,3,4,5
// Array.from(obj [, mapFn, thisArg]);
let arr = Array.from(range, num => num * num);
alert(arr);        // 1,4,9,16,25