이터러블과 유사 배열 객체

iterable(반복 가능한) 객체란 for..of 문을 사용할 수 있는 객체를 의미합니다. 좀 더 정확히 표현하자면 이터러블이란 Symbol.iterator 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은 객체를 말합니다. 대표적인 이터러블은 배열이 있습니다. 문자열 또한 이터러블입니다.

Symbol.iterator

이터러블 객체를 만들기 위해선 Symbol.iterator 메서드를 구현해야 합니다.

let range = {
  from: 1,
  to: 5,
};
 
range[Symbol.iterator] = function () {
  return {
    current: this.from,
    last: this.to,
 
    next() {
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    },
  };
};
 
for (let num of range) {
  alert(num); // 1, 2, 3, 4, 5
}

동작 순서는 다음과 같습니다.

  1. for..of호출 시 Symbol.iterator가 호출된다. Symbol.iteratoriterator 객체를 반환한다.
  2. 이후 for..of는 반환된 iterator 객체만을 대상으로 동작하며 이때 다음 값도 정해진다.
  3. 반복마다 next 메서드가 호출된다.
  4. done 프로퍼티가 true가 되면 반복문을 종료한다.

유사 배열 객체

유사 배열 객체란 indexlength 프로퍼티를 가지고 있어 배열처럼 보이는 객체를 의미합니다.

let arrayLike = {
  0: 'Hello',
  1: 'World',
  length: 2,
};
 
// 유사 배열 객체는 length 프로퍼티를 갖기 때문에 for 문으로 순회할 수 있습니다.
for (let i = 0; i < arrayLike.length; i++) {
  console.log(arrayLike[i]); // Hello World
  // 유사 배열 객체는 배열처럼 index를 통해 객체에 접근할 수 있습니다.
}
 
// 유사 배열 객체는 이터러블이 아니기 때문에 for..of 순회 불가
for (const key of arrayLike) {
  console.lang(key); // TypeError: Invalid attempt to iterate non-iterable instance.
}

for..in 문과 for..of 문의 차이

for..in문은 객체의 프로토타입 체인 상에 존재하는 모든 프로퍼티 중에서 프로퍼티 어트리뷰트 [[Enumerable]] 값이 true인 프로퍼티를 열거합니다. 단, 키가 Symbol인 프로퍼티는 열거하지 않습니다.

for..of문은 내부적으로 next() 메서드를 호출하여 순회하며 객체의 value 값을 할당하여 done프로퍼티가 true가 될 때까지 순회합니다.

Array.from()

Array.from() 메서드를 이용하여 유사 배열 객체 또는 이터러블을 배열로 변환할 수 있습니다.

let arrayLike = {
  0: 1,
  1: 2,
  length: 2,
};
 
const arr = Array.from(arrayLike);
arr.push(3);
console.log(arr); // [1, 2, 3]

참조