JavaScript - Iterable

Jinsung·2021년 8월 26일
0

javascript

목록 보기
6/11
post-thumbnail

🔍1. Iterable이란

반복 가능한 객체(iterable object)는 for...of 구문과 함께 ES2015에 도입되었습니다, 반복 가능한 객체를 다른 객체와 구분짓는 특징은, 객체의 Symbol.iterator속성에 특별한 형태의 함수가 들어있다는 것입니다.
객체는 Symbol.iterator속성에 특정한 형태의 함수가 들어있다면, 이를 반복 가능한 객체(iterable object) 혹은 줄여서 iterable이라 부르고, iterable protocol을 만족한다고 말합니다.

✅ 2. iterable 객체를 만들어내는 생성자

  • String
  • Array
  • TypedArray
  • Map
  • Set

✅ 3. iterable 의 사용

어떤 객체가 Iterable이라면, 그 객체에 대해서는 아래의 기능들을 사용할 수 있습니다.

  • for...of루프
  • spread 연산자(...)
  • 분해대입(destructuring assignment)
  • 기타 iterable을 인수로 받는 함수

즉, 문자열에 대해서도 위 기능들을 사용할 수 있습니다.

// for of
for(let c of 'hello') {
  console.log(c);
}
// spread 연산자
const characters = [...'hello'];
// 분해대입
const [c1, c2] = 'hello';
// Array from은 iterable 혹은 array-like 객체를 인수로 받습니다.
Array.from('hello');

✅ 4. Iterator Protocol

iterable객체는 iterable protocol을 만족한다. 즉, Symbol.iterator 속성에 특별한 형태의 함수가 저장되어 있다. Iterable protocol을 만족하려면, symbol.iterator 속성에 저장되어 있는 함수 iterator객체를 반환해야 합니다.

Iterator 객체는 아래의 특별한 조건을 만족하는 객체입니다.

  • Iterator는 next라는 메소드를 갖습니다.
  • next 메소드는 다음 두 속성을 갖는객체를 반환해야 합니다.
    • value - 현재 순서의 값을 나타냅니다.
    • done - 반복이 모두 끝났는지 나타냅니다.

위 조건을 iterator protocol 이라고 합니다.

// 문자열은 iterable이므로 이로부터 iterator를 생성할 수 있습니다.
const strIterator = 'go'[Symbol.iterator]();
strIterator.next(); // { value: 'g', done: false }
strIterator.next(); // { value: 'o', done: false }
strIterator.next(); // { value: undefined, done: true }
strIterator.next(); // { value: undefined, done: true }

✅ 5. Generator 함수

우리는 직접 iterable인 객체를 만들 수 있을까요? 답은 Yes입니다 iterable protocol을 구현하기만 하면 어떤 객체든 iterable이 될 수 있습니다.

Iterable 구현하기 가장 쉬운 방법은 ES2015에 도입된 generator 함수를 사용하는 것입니다.

// generator 함수 선언하기
function* gen1(){
  // ...
}
// 표현식 사용하기
const gen2 = function*(){
  // ...
}
// 메소드 문법으로 사용하기
const obj = {
  * gen(){
    // ...
  }
}

Generator 함수를 호출하면 객체가 생성되는데, 이객체는 iterable protocol을 만족합니다. 즉 Symbol.iterator속성을 가지고 있습니다.

✅ 6. Symbol.iterator

for..of가 동작하기위해서는 객체에 Symbol.iterator(특수 내장 심볼)메서드를 추가하여 아래의 순서가 진행되어야 합니다.
1. for..of가 시작되자마자 for..ofSymbol.iterator를 호출 Symbol.iterator가 없다면 에러가 발생, Symbol.iterator는 반드시 iterator(메서드 next가 있는 객체) 를 반환해야 함
2. 이후 for..of는 반환된 객체(iterator)만을 대상으로 동작
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) {
  alert(num); // 1, then 2, 3, 4, 5
}

관심사의 분리(Separation of concern,SoC)

  • range엔 메서드 next()가 없음
  • range[Symbol.iterator]() 를 호출해서 만든 iterator 객체와 이 객체의 메서드 next()에서 반복에 사용될 값을 만들어냄

객체를 iterator로

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

  [Symbol.iterator]() {
    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) {
  alert(num); // 1, then 2, 3, 4, 5
}
  • range[Symbol.iterator]()가 객체 range를 반환, 반환된 객체엔 필수 메서드 next()가 있고 this.current에 반복이 얼마나 진행 되었는지 나타내는 값도 저장되어 있음

✅ 7. Iterable과 유사 배열

이터러블과 유사 배열은 비슷해 보지만 정의와 특성이 다릅니다.

  • 이터러블(iterable) - Symbol.iterator가 구현된 객체 (for..of사용 가능)
  • 유사 배열(array-like) - indexlength 프로퍼티가 있어서 배열처럼 보이는 객체

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

Array.from 을 사용하여 이터러블이나 유사 배열을 진짜 Array로 만들 수 있습니다. 이 과정을 거치면 이터러블이나 유사 배열에도 배열 메서드를 사용 할 수 있습니다.

let arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
};
let arr = Array.from(arrayLike); //(*)
console.log(arr.pop()); // World 

자료 출처
https://ko.javascript.info/iterable - 모던 자바스크립트 튜토리얼
https://helloworldjavascript.net/pages/260-iteration.html - hello javascript

0개의 댓글