[JavaScript] Symbol 값과 이터러블 - 2

Hyuk·2023년 2월 12일
0

Symbol 값과 이터러블 1편에서 배열은 이터러블이기 때문에 이터러블의 속성을 통한 for ...of 의 동작 원리를 알 수 있었다.

const arr = [1, 2, 3]
let iterator = arr[Symbol.iterator]();

iterator.next()   // { value: 1, done: false }
iterator.next()   // { value: 2, done: false }
iterator.next()   // { value: 3, done: false }
iterator.next()   // { value: undefined, done: true }
for (const a of arr) {
	console.log(a);   // 1 2 3
}

그럼 해당 이터러블을 직접 구현해보자.

사용자 정의 이터러블

다시 한번 정의를 살펴보면 다음과 같다.

이터러블은 이터레이터를 리턴하는 [Symbol.iterator]() 를 가진 값이다.
이터레이터{ value, done } 을 리턴하는 next() 를 가진 값이다.
이터러블/이터레이터 프로토콜은 이터러블을 for ...of, 전개 연산자 등과 함께 동작하도록 한 규약을 뜻한다.

위의 정의까지 코드로 구현하면 다음과 같다.

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

well-formed-iterator

Symbol.iterator() 를 통해 리턴된 이터레이터 또한 Symbol.iterator() 값을 가지고 있다.
즉, 이터러블이면서 이터레이터인 객체를 생성한다.

const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();

iterator[Symbol.iterator]   // ƒ [Symbol.iterator]() { [native code] }

또한 해당 이터레이터 값을 실행한 값은 자기 자신을 뜻한다.

console.log(iterator[Symbol.iterator]() === iterator)   // true

이를 well-formed iterable 이라고 한다.

이러한 well-formed iterable 를 사용자 정의 이터러블 코드에 적용시킨다면 다음과 같다.

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

well-formed-iterator의 개념적 정의는 위와 같은데, 이를 구현하는 이유에 대해서 유인동님께서는 이렇게 답변해주셨다.

이터레이터여도 for ...of 나 전개연산자 등으로 남은 값을 소비할 수 있게 하기 위해서입니다. :)

profile
프론트엔드 개발자

0개의 댓글