똑같은 삽질은 2번 하지 말자

Javascript ES6+ 에서 함수형 프로그래밍(리스트 순회, Iterable Iterator 프로토콜 ) 본문

Javascript

Javascript ES6+ 에서 함수형 프로그래밍(리스트 순회, Iterable Iterator 프로토콜 )

곽빵 2021. 8. 16. 22:46

기존과 달라진 ES6에서의 리스트 순회

for i++ -> for of

const list = [1, 2, 3];
for (var i = 0; i < list.length; i++) {
  console.log(list[i]);
}
const str = 'abc';
for (var i = 0; i < str.length; i++) {
  console.log(str[i]);
}

// ES6 +
for (const a of list) {
  console.log(a);
}
for (const a of str) {
  console.log(a);
}
  • 상당히 간결하게 바뀌었다.
  • 어떻게 리스트를 순회할까 명령적인 방식에서 선언적으로 바뀌었다

그냥 간결하게 바뀌었다는 것, 이상의 의미가 있는데 ES6이 개발자들에게 어떠한 규약을 제시해 주었고 어떻게 순회에 대해서

추상화를 했고, 어떻게 사용하도록 했는지 ? 에 대해서 알아보자

 

Iterable & Iterator

for .. of.. 은 어떻게 순회를 하고 있을까?

우선 일반적인 index를 이용한 접근이 아니라는것을 이하의 코드로 알 수 있다.

<script>
  log('Set -----------');
  const set = new Set([1, 2, 3]);
  for (const a of set) log(a); // 1 2 3 출력
</script>

for of 문을 이용하면 내부의 요소들에 하나하나 접근해서 출력을 해주고 있지만.

index로 접근

위의 사진처럼 보통의 for문 처럼 index로는 접근이 불가능하다.

그럼 어떻게 ? Symbol.iterator 를 이용한 것이다.

set에 Symbol.iterator가 함수의 형태? 로 들어있다.

Symbol.iterator란 무엇인가? 어떻게 이걸 이용하는가? 

그걸 알기 위해선 Iterable/Iterator 프로토콜 이란 무엇인지를 알아야한다.

 

Iterable/Iterator 프로토콜

  • Iterable: Iterator 리턴하는 [Symbol.iterator]() 를 가진 값 -> Array, Set, Map등은 Iterable이다.
  • Iterator: { value, done } 객체를 리턴하는 next() 를 가진 값
  • Iterable/Iterator 프로토콜: Iterable을 for...of, 전개 연산자 등과 함께 동작하도록한 규약

위의 프로토콜에 의해 for..of, 전개 연산자를 통한 Iterable(Array, Set, Map...) 들의 순회가 가능한 것이다.

let iterator = set[Symbol.iterator]();
iterator.next(); // 1
iterator.next(); // 2
iterator.next(); // 3

iterator를 이용한 객체의 순회, 더 이상 값이 없을시 done:true

 

그럼 iterable을 어떻게 구현할 수 있을까?

 

const iterable = {
  [Symbol.iterator]() {
    let i = 3;
    return {
      next() { // value, done을 리턴하는 next() 
        return i == 0 ? {done: true} : {value: i--, done: false};
      },
      [Symbol.iterator]() { // 자기자신 Symbol.iterator를 리턴하는 [Symbol.iterator]()
        return this;
      }
    }
  }
};

 

이터러블은 Symbol.iterator를 가지고 있고 Symbol.iterator을 실행하면 자기자신을 return한다.

const iter = arr[Symbol.iterator]() // 이터레이터
const iter2 = iter[Symbol.iterator]() // 이것도 이터레이터

이렇게 된 이터러블이 Well-formed Iterable이라고 불리어진다.

 

 

그럼 iterable/iterator들은 어디에서 쓸수있나?

javascript에서 내장된 친구들(Array, Map, Set...) 만 이 프로토콜을 따르는게 아니라 오픈 라이브러리에서 순회가능한 친구라 하면 

대부분 iterable/iterator프로토콜을 따르고있다. 그리고 Web APIs에 있는 dom과 관련된 친구들도 이 프로토콜을 따르고있다.

 

참고로 전개 연산자(... ) 도 이 프로토콜을 따르고있다.

const a = [1, 2];
// a[Symbol.iterator] = null;
console.log(...a); // 위의 iterable을 null로 한다면 iterable이 아니다 라는 에러가 발생

 

 

*참고

https://gist.github.com/qodot/ecf8d90ce291196817f8cf6117036997

 

ES6의 심볼, 이터레이터, 제네레이터에 대해 알아보자

ES6의 심볼, 이터레이터, 제네레이터에 대해 알아보자. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

 

Comments