ES6에서 도입된 Iteration protocol은 iterable 한 자료구조를 만들기 위한 ECMAScript 사양에 정의한 규칙이다.
ES6 이전의 순회 가능한 여러 데이터 컬렉션들은 통일된 규약 없이 나름의 구조로 순회를 할 수 있게 구현되어있었지만 ES6에서는 순회 가능한 자료구조를 iteration protocol을 준수하는 iterable로 통일하였다.
Iteration protocol의 개념은 상당히 말장난 같아서 많이 헷갈린다. 한번 정리를 해야 ES6 이상의 여러 개념을 이해하는데 도움이 될 것 같아서 정리하려고 한다.
Iterable
이터러블 프로토콜을 준수한 객체를 이 트러블이라고 한다.
여기서의 Iterable protocol이란 Well-known Symbol인 Symbol.iterator를 프로퍼티 키로 사용한 메서드를 구현하거나 상속받은 Symbol.iterator 메서드를 호출하면 Iterator protocol을 준수한 iterator를 반환한다. 이러한 규약을 이터러블이 터러블 프로토콜이라고 하며, 이 터러블 프로토콜을 준수한 객체를 iterable을라고 한다.
결국 Iterable protocol은 Symbol.iterator 메서드의 결과로 Iterator protocol을 준수한 iterator를 반환함을 약속하는 것이다.
그럼 해당 개념에서 나온 Iterator protocol, 즉 이터레이터 프로토콜에 대해서도 알아야 한다.
Iterator protocol
Iterable의 Symbol.iterator 메서드를 호출하면 iterator protocol을 준수한 iterator를 반환하는 것을 iterable protocol이라고 했다. 이 반환된 iterator는 next()라는 메서드를 소유하며, next() 메서드의 반환 값은 { value, done } 프로퍼티를 갖는 iterator result object (이터레이터 리절트 객체)를 반환한다. 즉 next()메서드를 가져야 하며 반환 값은 이터레이터 리절트 객체를 반환한다는 규약을 iterator protocol이라고 한다. 이러한 규약을 지킨 객체를 iterator라고 한다. 이터레이터 객체는 이 터러블의 요소를 탐색하기 위한 포인터 역할을 한다.
정리
iterable이라는 객체는 Symbol.iterator를 프로퍼티의 key로 가진 메서드를 가지며 해당 리턴 값은 이터레이터 프로토콜을 준수한 이터레이터 객체이며, 그 객체는 next() 메서드를 가지고 next()의 리턴 값은 value, done을 프로퍼티로 가진 이터레이터 리절트 객체이다.
iterable = {
[Symbol.iterator]() {
return { //이터레이터 객체
next() {
return { value : any, done : boolean};
}
}
}
}
예를 들면 배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블이다. 이 트러블은 for.. of문으로 순회할 수 있으며, 스프레드 문법, 디스트럭처링 할당의 대상으로 사용이 가능하다.
그럼 일반 우리가 사용하는 일반객체는 왜 스프레드, 디스트럭처링 할당이 가능할까?
이는 2021년 1월 TC39 프로세스의 stage 4단계에 제안되어 있는 스프레드 프로퍼티 제안은 일반 객체에 스프레드 문법의 사용을 허용하기 때문이다.
built-in iterable
자바스크립트는 이터레이션 프로토콜을 준수한 빌트인 이 트러블을 제공한다.
- Array.prototype [Symbol.iterator]
- String.prototype [Symbol.iterator]
- Map.prototype [Symbol.iterator]
- Set.prototype [Symbol.iterator]
- TypedArray.prototype [Symbol.iterator]
- arguments.prototype [Symbol.iterator]
- NodeList.prototype [Symbol.iterator]
- HTMLCollection.prototype [Symbol.iterator]
* 왜 이터레이션 프로토콜이 필요했을까?
- 각자의 방법대로 순회의 방법을 가진 구현체들이 있다면, 새로운 기능을 추가할 때 각자의 방법을 모두 지원해야 하는 일이 생긴다. 그래서 interface가 필요했는데 이러한 이터레이션 프로토콜이 interface역할을 한다.
Example
const fibo = function () {
let [pre, cur] = [0 , 1];
return {
[Symbol.iterator]() { return this;},
next() {
[pre,cur] = [cur, pre + cur];
return {value: cur}; //무한 수열 done 생략
}
};
};
for (const num of fibo()){
if (num > 10000) break;
console.log(num);
}
'JavaScript' 카테고리의 다른 글
this (0) | 2022.02.04 |
---|---|
함수, 1급 객체 (0) | 2022.01.25 |
Symbol (0) | 2022.01.16 |
JS의 부정확한 계산 (0) | 2021.12.03 |
export, import (0) | 2021.11.28 |
댓글