JS (34) - 이터러블

최조니·2022년 8월 10일
0

JavaScript

목록 보기
31/36

34.1 이터레이션 프로토콜

이터레이션 프로토콜
순회 가능한 데이터 컬렉션(자료구조)을 만들기 위해 ECMA 사양에 정의하여 약속한 규칙

  • 이터러블 프로토콜
  • 이터레이터 프로토콜

1) 이터러블

이터러블
이터러블 프로토콜을 준수한 객체

  • Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은 객체
const isIterable = v => v !== null && typeof v[Symbol.iterator] === 'function';

isIterable([]);			// true
isIterable('');			// true
isIterable(new Map());	// true
isIterable(new Set());	// true
isIterable({});			// false
  • Symbol.iterator 메서드를 직접 구현하지 않거나 상속받지 않은 일반 객체는 이터러블 프로토콜을 준수한 이터러블이 아님
    for...of 문으로 순회 불가, 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용 불가

2) 이터레이터

  • 이터러블의 Symbol.iterator 메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터 반환

  • 이터러블의 Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 가짐

  • 이터레이터의 next 메서드는 이터러블의 각 요소를 순회하기 위한 포인터 역할
    next 메서드를 호출하면 이터러블을 순차적으로 한 단계씩 순회하며 순회 결과를 나타내는 이터레이터 리절트 객체 반환

  • 이터레이터 리절트 객체

    • value 프로퍼티 : 현재 순회 중인 이터러블의 값
    • done 프로퍼티 : 이터러블의 순회 완료 여부
const array = [1, 2, 3];
const iterator = array[Symbol.iterator]();

console.log('next' in iterator);	// true
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}

34.2 빌트인 이터러블

표준 빌트인 이터러블

빌트인 이터러블Symbol.iterator 메서드
ArrayArray.prototype[Symbol.iterator]
StringString.prototype[Symbol.iterator]
MapMap.prototype[Symbol.iterator]
SetSet.prototype[Symbol.iterator]
TypedArrayTypedArray.prototype[Symbol.iterator]
argumentsarguments[Symbol.iterator]
DOM 컬렉션NodeList.prototype[Symbol.iterator]
HTMLCollection.prototype[Symbol.iterator]

34.3 for ... of 문

for ... of
이터러블을 순회하면서 이터러블의 요소를 변수에 할당

for ... of 문 선언

for (변수선언문 of 이터러블) { ... }
  • for ... of문은 for ... in 문과 유사하지만,
    • for ... in 문 - [[Enumerable]] 값이 true인 프로퍼티를 순회하며 열거
    • for ... of 문 - 내부적으로 이터레이터의 next 메서드를 호출하여 이터러블 순회
for (const item of [1, 2, 3]) {
  console.log(item);	// 1, 2, 3
}

34.4 이터러블과 유사 배열 객체

유사 배열 객체
마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고 length 프로퍼티를 갖는 객체

  • for문으로 순회 가능하고, 인덱스로 프로퍼티 값 접근 가능

  • 유사 배열 객체는 이터러블이 아닌 일반 객체
    Symbol.iterator 메서드가 없으므로 for...of 문으로 순회할 수 없음❗️

const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

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  
  • 배열, arguments, NodeList, HTMLCollection유사 배열 객체이면서 이터러블
    • Array.from 메서드를 사용해서 배열로 변환하여 반환
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

const arr = Array.from(arrayLike);
console.log(arr);	// [1, 2, 3]

34.5 이터레이션 프로토콜의 필요성

이터레이션 프로토콜
다양한 데이터 공급자가 하나의 순회 방식을 갖도록 규정하여 데이터 소비자가 효율적으로 다양한 데이터 공급자를 사용할 수 있도록,
데이터 소비자와 데이터 공급자를 연결하는 인터페이스 역할


34.6 사용자 정의 이터러블

1) 사용자 정의 이터러블 구현

const fibonacci = {
  [Symbol.iterator]() {
    let [pre, cur] = [0, 1];
    const max = 10;
    
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { value: cur, done: cur >= max };
      }
    };
  }
};
      
for (const num of fibonacci) {
  console.log(num);		// 1 2 3 5 8
}

const arr = [... fibonacci];
console.log(arr);

const [first, second, ...rest] = fibonnaci;
console.log(first, second, rest);	// 1 2 [3, 5, 8]

2) 이터러블을 생성하는 함수

const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];
  
  return {
    [Symbol.iterator] () {
      return {
        next() {
          [pre, cur] = [cur, pre + cur];
          return { value: cur, done: cur >= max };
        }
      };
    }
  };
};

for (const num of fibonacciFunc(10)) {
  console.log(num);		// 1 2 3 5 8
}

3) 이터러블이면서 이터레이터인 객체를 생성하는 함수

const iterable = fibonacciFunc(5);
const iterator = iterable[Symbol.iterator]();

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: 5, done: false }

4) 무한 이터러블과 지연 평가

const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];
  
  return {
    [Symbol.iterator] () { return this; },
    next () {
      [pre, cur] = [cur, pre + cur];
      return { value: cur };
    }
  };
};

for (const num of fibonacciFunc()) {
  if (num > 10000) break;
  console.log(num);	// 1 2 3 5 8 ... 4181 6765
}

const [f1, f2, f3] = fibonacciFunc();
console.log(f1, f2, f3);	// 1 2 3
profile
Hello zoni-World ! (◍ᐡ₃ᐡ◍)

0개의 댓글