ES2015에서 Iterable Protocol이 추가되었습니다.
Iterable Protocol에는 2가지 형태가 존재하는데, iterable과 iterator가 있습니다.
Iterable
iterable은 객체의 멤버를 반복할 수 있는 객체입니다.
iterable은 자바스크립트 객체의 요소들에 대해 반복되는 행동(예를 들어, for .. of 구문에서 어떤 값들이 루프를 돌고 있는가)을 정의할 수 있도록 해줍니다.
JavaScript에서 객체가 iterable하기 위해서는, object에는 [@@iterator] 메서드가 구현되어 있어야 합니다.
따라서 임의로 우리가 객체를 만들고 iterable하게 만들고 싶다면, object 프로퍼티에 Symbol.iterator를 추가해야 합니다.
객체는 반드시 하나의 Symbol.iterator 만을 가질 수 있습니다.
const iterable = new Object();
// obj[Symbol.iterator] 함수는 iterator 객체를 반환합니다.
iterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
// 전개 연산자를 이용해서 iterator의 값을 반복할 수 있습니다.
console.log([...iterable]); // 1 2 3
// for ... of 를 이용해서 iterator의 값을 반복할 수 있습니다.
for(var value of iterable) {
console.log(value); // 1 2 3
}
객체가 iterated 될 때, @@iterator 메서드가 인자 없이 호출되고, @@iterator가 반환하는 iterator는 iterated되는 값들을 얻기 위해 사용됩니다.
@@iterator 메서드는 호출한 후 iterable한 객체를 반환하므로 generator 함수라고도 할 수 있습니다.
Iterator
iterator 는 객체를 next 메서드로 순환할 수 있는 객체입니다.
iterator는 next() 메소드를 가지고 있고, next 메소드는 아래의 규칙에 따라 구현되어야 합니다.
- next 메소드는 arguments 가 없습니다.
- next 메소드는 done: boolean 과 value: any 를 포함하는 object 를 반환해야 합니다.
- next 메소드의 반복이 끝날때 done 은 true 를 반환해야 합니다.
const iterator = '132'[Symbol.iterator]();
iterator.next(); // {value: "1", done: false}
iterator.next(); // {value: "3", done: false}
iterator.next(); // {value: "2", done: false}
iterator.next(); // {value: undefined, done: true}
iterator 객체는 아래와 같이 만들 수 있습니다.
const obj = {};
// iterator를 생성하는 함수
// iterator는 이 함수의 반환값입니다.
const counter = count => (
(i = 0) => ({
next: () => (
(i++ < count) ?
{ value: i, done: false } :
{ value: 0, done: true }
)
})
);
obj[Symbol.iterator] = counter(3);
console.log([...obj]); // [1, 2, 3]
Iterable 과 Iterator 의 구분
Object가 @@iterator 를 가지고 있다면, iterable 입니다.
Object에서 next 메서드가 값을 반복하면서, {done, value} 를 반환한다면, iterator 입니다.
Iteration protocols 의 예시
Javascript 에서 built-in object 중 iterable 를 가지고 있는 객체는 Array, TypedArray, String, Map, Set 가 있으며 이들의 메서드 중 일부는 iterator 객체를 반환합니다. 대표적으로 Object.entries( ), Object.keys( ), Object.values( ) 메서드 등이 있습니다.
- Object.entries( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성 [key, value] 쌍의 배열을 리턴합니다.
- Object.keys( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성의 key 이름들로 이루어진 배열을 리턴합니다.
- Object.values( ) : 전달된 파라미터 객체가 가지는 (열거 가능한) 속성의 값들로 이루어진 배열을 리턴합니다.
const arr = ['1', '2', '3'];
console.log([...arr.entries()]);
// [[0, '1'], [1, '2'], [2, '3']];
console.log([...arr.keys()]);
// [0, 1, 2];
console.log([...arr.values()]);
// ['1', '2', '3'];
const map = new Map([[1, '1'], [2, '2'], [3, '3']]);
console.log(map.entries());
// MapIterator {1 => "1", 2 => "2", 3 => "3"}
console.log(map.keys());
// MapIterator {1, 2, 3}
console.log(map.values());
// MapIterator {"1", "2", "3"}
const set = new Set([1, 2, 3]);
console.log(set.entries());
// SetIterator {1, 2, 3}
console.log(set.keys());
// SetIterator {1, 2, 3}
console.log(set.values());
// SetIterator {1, 2, 3}
문자열의 기본적인 iterator는 문자열의 요소들을 하나씩 반환합니다.
전개 연산자 또한 기본적으로 동일한 iteration protocol을 사용합니다.
let someString = 'hello';
let iterator = someString[Symbol.iterator]();
console.log(iterator + ''); // "[object String Iterator]"
console.log(iterator.next()); // {value: 'h', done: false }
console.log(iterator.next()); // {value: 'e', done: false }
console.log(iterator.next()); // {value: 'l', done: false }
console.log(iterator.next()); // {value: 'l', done: false }
console.log(iterator.next()); // {value: 'o', done: false }
console.log(iterator.next()); // {value: undefined, done: true }
console.log([...someString]); // ['h', 'e', 'l', 'l', 'o']
우리가 직접 @@iterator를 정의하여 iteration 특성을 재정의해봅시다.
// need to construct a String object explicitly to avoid auto-boxing
let someString = new String('hello');
someString[Symbol.iterator] = function () {
return {
// this is the iterator object, returning a single element (the string "bye")
next: function () {
return this._first ? {
value: 'bye',
done: (this._first = false)
} : {
done: true
}
},
_first: true
};
};
console.log([...someString]); // ["bye"]
console.log(someString + ''); // "hello"
'프로그래밍 언어 > JavaScript' 카테고리의 다른 글
[JavaScript] for, foreach, filter, map, reduce 기능 및 퍼포먼스의 차이 (2) | 2022.09.24 |
---|---|
Generator (0) | 2020.11.23 |
Node와 Element (0) | 2020.11.22 |
DOM, CSSOM, BOM은 무엇일가? (0) | 2020.11.22 |
자바스크립트 모듈(Module) (0) | 2020.11.21 |