[JS] Iterable 과 Iterator 그리고 유사배열객체

Jay ·2022년 4월 30일
0

1.이터러블

이터러블 프로토콜을 준수하는 객체를 이터러블이라 한다.
즉, 프로퍼티 키로 사용한 메서드를 직접 구현하거나, Symbol.iterator를 프로토타입 체인을 통해 상속받아 호출받으면 이터레이터를 반환할 때, 이를 이터러블 프로토콜을 준수한다고 한다.
이터러블은 for ... of 문으로 순회가능하며 스프레드문법, 배열 디스트럭처링의 대상으로 사용가능하다.

1-1.이터레이터

이터레이터는 next 메서드를 소유하며 next를 호출하면 이터러블을 순회하며 value와 done 프로퍼티를 갖는 이터레이터 리저트 객체를 반환. 이러한 규약을 이터레이터 프로토콜이라하며 이 규약을 지키는 객체를 이터레이터라 한다.

1-2.순회가능하다? == 이터러블하다

String.prototype[@@iterator]
Array.prototype[@@iterator]
+TypeArray, arguments, DOM 컬렉션

1-3.for ... of vs for ... in

for ... of

1) MDN 정의 :
for ... of 명령문은 반복가능한 객체 (Array, Map, Set, String, TypedArray, arguments 객체 등을 포함)에 대해서 반복하고 각 개별 속성값에 대해 실행되는 문이 있는 사용자 정의 반복 후크를 호출하는 루프를 생성합니다.

2) Deep dive 정의 :
for ... of 문은 내부적으로 이터레이터의 next 메서드를 호출하여 이터러블을 순회하며 next 메서드가 반환한 이터레이터 리절트 객체의 value 프로퍼티 값을 for ... of 문의 변수에 할당한다. 그리고 이터레이터 리절트 객체의 done 프로퍼티 값이 false이면 이터러블의 순회를 계속하고 true이면 이터러블의 순회를 중단한다.

for (const item of [1,2,3]) {
	console.log(item);

-> 모든 객체보다는, [Symbol.iterator] 속성이 있는 모든 컬렉션 요소에 대해 이 방식으로 반복한다.(컬렉션 전용)

for ... in

1) MDN 정의 :
for...in문은 상속된 열거 가능한 속성들을 포함하여 객체에서 문자열로 키가 지정된 모든 열거 가능한 속성에 대해 반복합니다. (Prototype 포함, Symbol로 키가 지정된 속성은 무시.)

2) Deep dive 정의 :
객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 true인 프로퍼티를 순회하며 열거(enumeration)한다. 이 때 프로퍼티 키가 심벌인 프로퍼티는 열거하지 않는다.

-> 순회시 순서가 보장되지 않는다. value가 아니라 key값을 순회한다. 따라서 배열순회시 사용할 수 없다.
-> 쉽게 객체 속성을 확인할 수 있기 때문에 디버깅에 사용될 수 있다. 데이터의 저장에 있어서는 배열이 더 실용적이지만, 키-값 쌍이 선호되는 데이터의 경우 특정 값 유무 체크를 위해 for ... in 을 사용할 수 있다.

1-4 Set, Map?

자바스크립트의 빌트인 이터러블

2.유사 배열 객체

배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고, length 프로퍼티를 갖는 객체.
length 프로퍼티를 갖기 때문에 배열처럼 for문으로 순회가능하며, 인덱스로 프로퍼티 값에 접근 가능.

유사배열객체는 Symbol.iterator 메서드가 없기 떄문에 iterable이 아니며 따라서 for ... of 문으로 순회 불가능.

단 arguments, NodeList, HTMLCollection은 유사배열 객체이면서 이터러블이다.
왜냐하면, ES6에 이터러블이 도입되면서 Symbol.iterator 메서드를 구현하였기 떄문에.

그렇다면 빌트인 이터러블 Set, Map은 ??
-> iterable 객체이지만 배열은 아니다.
-> 배열의 경우 Prototype의 Symbol.iterator를 상속받기 때문에
-> 이터러블과 배열의 차이점은 Protytype의 차이에서 기인한다?

3.배열

Array.prototype@@iterator
Array.prototype.length

4.Iteration 프로토콜이 필요한 이유?

ES6 이전의 순회가능한 데이터 컬렉션(배열,문자열,유사배열객체,DOM 컬렉션 등)dms 통일된 규약 없이 각자 나름의 구조를 가지고 for문 for...in문, foreach 메서드 등 다양한 방법으로 순회할 수 있었다.
ES6에서는 순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 for...of문, 스프레드 문법, 배열디스트럭처링 할당의 대상으로 사용할 수 있도록 일원화하였다.
따라서 이터러블은 for...of문, 스프레드문법, 배열 디스트럭처링과 같은 데이터 소비자에 의해 사용되므로 데이터 공급자의 역할을 한다고 할 수 있다

1) 데이터 공급자
Array, String, Map/Set, DOM 컬렉션

2) 데이터 소비자
for...of문, 스프레드문법, 배열 디스트럭처링, Map/SEt 생성자.

5. 사용자 정의 이터러블

이터레이션 프로토콜을 준수하지 않는 일반 객체도 이터레이션 프로토콜을 준수하도록 구현하면 사용자 정의 이터러블이 된다.

// 피보나치 수열을 구현한 사용자 정의 이터러블
const fibonacci = {
  // Symbol.iterator 메서드를 구현하여 이터러블 프로토콜을 준수한다.
  [Symbol.iterator]() {
    let[pre, cur] = [0,1];
    const max = 10; // 수열의 최대값 설정
    
    //Symbol.iterator 메서드는 next 메서드를 소유한 이터레이터를 반환해야 하고
    // next 메서드는 이터레이터 리절트 객체를 반환해야 한다.
    return {
      next() {
        [pre,cur] = [cur,pre + cur];
        //이터레이터 리절트 객체를 반환한다.
        return { value: cur, done: cur >=max};
      }
    };
  }
};

// 이터러블인 fibonacci 객체를 순회할 때마다 next 메서드가 호출된다.
for(const num of fibonacci){
  console.log(num); // 1 2 3 5 8
}
profile
Jay입니다.

0개의 댓글