[JavaScript] 이터러블

zmin·2022년 4월 28일
0
post-thumbnail

모던 자바스크립트 Deep Dive, 이웅모

이터레이션 프로토콜

순회가능한 자료구조를 위해 ECMAScript 사양에 정의하여 미리 약속한 규칙

이터레이션 프로토콜의 등장 이전에는 각 자료 구조가 각각의 순회 방법에 따라 데이터를 순회함(배열과 인덱스같이)
효율적이지 않음, 이를 소비하는 우리가 각각의 자료구조에 대해 순회방식을 고려해주어야함

그래서 데이터 공급자가 다양한 자료구조들이 이터레이션 프로토콜을 준수하도록 설정했고 소비자는 이에 맞추어 이터레이션 프로토콜을 지원하는 순회 방식만을 사용하면 됨

데이터 소비자와 공급자를 연결하는 인터페이스 역할

  • 이터러블 프로토콜
    객체 에 상속받은 Symbol.iterator이나 직접 구현한 [Symbol.iterator](){...}는 호출 시에 아래 프로토콜을 준수한 이터레이터를 반환 → 이런 규칙이 이터러블 프로토콜, 이를 만족하는 객체이터러블

  • 이터레이터 프로토콜
    객체next 메서드를 소유하며 이 메서드는 이터러블을 순회하며 value, done프로퍼티를 가지는 이터레이터 리절트 객체를 반환 → 이런 규칙이 이터레이터 프로토콜, 이를 만족하는 객체이터레이터(포인터 역할)

    {	// 객체임
      next() {
        .. // 보통 연산 내용이 여기 들어가는 듯, next가 한 번 호출되면 값이 다음으로 넘어가는 형태
        return {value:, done: 순환 끝 여부};
      }
    }		

이터러블의 경우 for...of 문으로 순회할 수 있으며 디스트럭처링 할당 가능

빌트인 이터러블

따로 설정해주지 않아도 되는 이터러블들 → 바로 사용가능

빌트인 이터러블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]

사용자 정의 이터러블

일반 객체에 [Symbol.iterator] 메서드를 구현

const obj = {
  [Symbol.iterator](){
    let num = 0;
    const max = 10;
    return {
      // next 메소드를 가지는 이터레이터 반환
      next(){
        num++;
        return { value: num, done: num >= max };	// 리절트 객체
      }
    };
  }
}

다음과 같이 this를 이용하면 이터러블이면서 이터레이터인 객체를 반환하는 함수를 만들 수 있음

const count = function(start){
  let num = start;
  // 객체 반환
  return {
    // 현재 객체([Symbol.iterator], next 메소드 존재) 반환하는 [Symbol.iterator] 메서드
    [Symbol.iterator](){ return this; }
    
    // next 메소드
    next(){
      num++;
      return { value: num, done: num >= max };	// 리절트 객체
    }
  };
};

이터러블 활용

for...of

for(변수선언문 of 이터러블) { .. }

done 값이 true가 될 때까지 반복, true인 객체의 value는 사용되지 않음
다른 반복문들과 크게 차이는 없으나 이터러블에만 사용할 수 있음

무한 이터러블과 지연 평가

리절트 객체에 done프로퍼티를 제외하면 무한 이터러블을 구현할 수 있음

const count = function(start){
  let num = start;
  return {
    [Symbol.iterator](){ return this; }
    next(){
      num++;
      return { value: num };	// 종료조건 없음 -> 무한
    }
  };
};

const [a,b,c] = count(10);
console.log(a, b, c);	// 10 11 12

지연평가는 메모리를 미리 확보한 다음 이후 데이터를 공급하는 것이 아니라
실제 변수를 사용해야 할 때 메모리를 확보하고 데이터를 생성하여 할당하는 기법, 결과가 필요할 때 까지 평가를 늦추는 기법 → next 메서드가 호출될 때 데이터가 생성

  • 실행속도가 빠름
  • 불필요한 메모리 사용 줄임
  • 무한하게 표현 가능

스프레드 문법

이터러블한정 문법
이터러블의 값들을 펼쳐서 목록으로 만듦
값이 아님, 그렇지만 함수의 인수로는 전달 가능

const arr = [1, 2, 3];

// 아래 두 줄은 동일
anyFunction.apply(null, arr);
anyFunction.call(null, ...arr);

배열

// 얕은 복사
const arr1 = [...arr];	// [1, 2, 3]
const arr2 = [7, 8];

const mergedArr = [...arr1, ...arr2];	// [1, 2, 3, 7 ,8]

스프레드 프로퍼티 제안
공식적이진 않지만 이터러블이 아닌 일반객체의 프로퍼티에 대해서 스프레드 문법을 적용하는 것이 제안되어 있음

const obj1 = { foo: 'bar', x: 42 };
const obj2 = { foo: 'baz', y: 13 };

const clonedObj = { ...obj1 };	// 얕은 복사

// 동일한 프로퍼티가 있느느 경우 뒤쪽에 있는 값으로 할당
const mergedObj = { ...obj1, ...obj2 };	// { foo: "baz", x: 42, y: 13 }

Rest 파라미터??

와 다름
Rest 파라미터는 인수로 전달된 값의 목록을 모아 배열을 만드는 것이고
스프레드 문법은 배열을 포함하는 이터러블들을 펼쳐 값의 목록을 만드는 것

function f(...rest){
  console.lot(rest);
}

f(...[1,2,3]);

비구조화 할당

말 그대로 구조화 되어있는 이터러블 또는 객체를 비구조화시켜 1개 이상의 변수에 할당하는 것

배열

우변에 무조건 이터러블이 와야함
배열의 인덱스, 즉 순서를 기준으로 할당함

const arr = [1, 2, 3];

const [a, b] = arr; // a=1, b=2
const [a1, a2, a3, a4] = arr; // a1=1, a2=2, a3=3, a4=undefined (부족하면 undefined 할당)
const [b1, , b2] = arr; // a1=1, a2=3

// 기본값 지정 가능하나 이터러블 값이 우선시됨
const [c1, c2, c3=11, c4=10] = arr; // a1=1, a2=2, a3=3, a4=10


// rest요소 사용가능, 가장 뒤에 와야함
const [d,...D] = arr; // d=1, D=[2, 3]

객체

프로퍼티 키를 이용하여 할당

const info = { lang:'javascript', book:'deepdive', hi:5};

// 순서와 갯수상관 없으나 프로퍼티 키가 일치해야함
const { book, lang } = info;	// book='deepdive', lang='javascript'
const { lang:l , hi:hello } = info;	// l='javascript', hello=5


// rest프로퍼티 사용가능, 가장 뒤에 와야함
const { book:BOOK,...obj } = info; // BOOK='deepdive', obj={ lang:'javascript', hi:5 }
profile
308 Permanent Redirect

0개의 댓글