Iterable 이란 무엇인가요? [Functional Programming]

Dengo·2023년 2월 16일
0

Functional Programming

목록 보기
1/2
post-thumbnail

인프런 유인동님의 함수형 프로그래밍 강의를 기반으로 작성하며 언어는 자바스크립트로 설명합니다.

리스트를 더 멋지게 순회하는 방법

흔히 반복문은 프로그래밍에서 조건문과 더불어 필수적인 요소로 사용되어지는데요.
가장 원시적인(?) 형태의 반복문을 살펴보겠습니다.

const arr = [1, 2, 3, 4, 5];
for (let i = 0 ; i < 5 ; i++) {
  console.log(arr[i]);
}

요것이 우리가 흔히 코딩을 처음 배울 때 사용하는 반복문의 패턴이죠.
어쩌면 이 패턴이 익숙하신 분들은 계속 이렇게 사용하고 있을지도 모르겠습니다.
저도 한동안은 그랬듯이요.

하지만 더 나은 반복문을 사용하는 방법은 따로 있습니다.

const arr = [1, 2, 3, 4, 5];
for (const v of arr) {
  console.log(v);
}

바로 이렇게 말 입니다.
뭔 큰 차이가 있냐고 궁금증이 생길 수 있는데,
위의 인덱스를 1씩 더해서 추가하는 방법과 arr의 '어떠한 조작'을 통해서 배열 값을 for of문을 통해서 하나씩 안전하게 빼내었다 라고 설명할 수 있겠네요.

Iterable이란??

for of 문에서 위와 같이 동작하는건 사실 배열 뿐 아니라 Map, Set과 같은 객체도 있습니다.
즉 Array, Map, Set은 for of 문을 동작 시킬 수 있습니다.

요렇게 '순회 가능한' 객체들을 통칭 Iterable 객체라고 부릅니다.

Iterable 객체의 공통점으로는 바로 Symbol.iterator 프로퍼티를 갖고 있다는 겁니다.
뭔말인지 모를거 같아서 사진으로 준비했는데요
바로 요런 느낌입니다.

보시면 배열을 Symbol.iterator라는 프로퍼티를 갖고 있고 뭔지는 모르겠지만 함수를 갖고 있다고 나오고 있죠?
해당 함수는 또 다음과 같은 모습입니다

() => Iterator객체

그래서 위의 콘솔에서 실행을 시켰을때 Iterator 객체를 반환하는 것을 볼 수 있습니다.

Iterable객체는 for of 문이나 스프레드 연산자 (...iterable)와 함께 활용될 수 있습니다.

Iterator란??

그냥 한글로 쓸게요... 영어로 쓰니까 힘들..
이터레이터란 next메서드를 갖는 객체를 이터레이터라고 하고,
이 next메서드는 다음 처럼 생긴 객체를 반환합니다.

{ value : 10, done : false }

value에서는 이터러블에서 순회하는 값이 차례로 나오고
done은 이터러블의 순회가 끝났는지를 알려주는 값입니다.
아래 예시는 arr = [10, 20, 30] 을 이터레이터를 이용해서 순회하는 모습입니다.

이것을 활용해서 for of 문을 직접 구현할 수도 있겠죠. 아래와 같이 말입니다.

// 우리가 아는 for of 문
for (const a of arr) { console.log(a) }

// 직접 구현한 for of 문
iter = iter[Symbol.iterator]();
let cur;
while (!(cur = iter.next()).done) {
  const a = cur.value;
  console.log(a)
}

Iterable 직접 만들어보기

위의 규칙만 지킨다면 이터러블을 직접 만들수도 있습니다.
아래는 3, 2, 1 순으로 순회하는 이터러블 예시입니다.

const exampleIterable = {
  [Symbol.iterator]() {
    let i = 3;
    return {
      next() {
        return i === 0 ? {done : true} : {value: i--, done : false};
      },
    }
  }
}

하지만 이렇게만 작성을 한다면 exampleIterable를 for of 문을 통해서 순회하는 것 자체는 가능하지만 exampleIterable의 iterator를 활용한 for of 순회는 이루어 지지 않습니다.

아예 이터러블이 아니라고 나오네요 ,,,
왜 일까요? 이터러블은 아니지만 분명 iterator와 next를 사용해서 순회하는것은 가능한데 말이죠.

Well-Formed Iterable

위와 같은 문제를 해결하기 위해선 이터러블이 갖는 이터레이터가 또 이터레이터를 갖게하면 됩니다.
이것을 Well-Formed Iterable 이라고 부릅니다.
위 코드는 다음과 같이 수정될 수 있습니다.

const exampleIterable = {
  [Symbol.iterator]() {
    let i = 3;
    return { // 이 반환 값이 이터레이터
      next() {
        return i === 0 ? {done : true} : {value: i--, done : false};
      },
      [Symbol.iterator]() { return this } 
      // 이터레이터가 또 자기 자신(이터레이터)을 반환하는 [Symbol.iterator]()를 갖게 한다.
    }
  }
}

이렇게 하면 아래의 코드 예시가 문제없이 동작할 수 있습니다.

iter자체가 이터레이터를 갖기 때문에, 스프레드 연산자를 활용해서 나머지 값을 빼내는 것이 가능해졌습니다.

정리

Iterable 이란?

임의의 객체 obj가 있습니다.
obj[Symbol.iterator]가

() => 이터레이터

이렇게 이터레이터를 반환하는 익명함수를 갖는다면 객체 obj는 Iterable이라고 합니다.

Iterator란?

일단은 객체입니다.
객체인데 next메서드를 갖는 객체입니다.
next메서드는 다음 형태의 객체를 반환하는 메서드입니다.

{value : 값 , done : 끝났는지 }

Well-Formed Iterable

이터레이터가 이터레이터를 갖는 이터러블입니다.
좀 더 자세히 말하면 이터레이터가 [Symbol.iterator]()를 갖는 이터러블을 뜻합니다.

참고

https://baeharam.netlify.app/posts/javascript/JS-Iterable과-Iterator

profile
Software Engineer (전산쟁이)

0개의 댓글