본 게시글은 인프런 함수형 프로그래밍과 JavaScript ES6+ 강의를
개인적으로 공부하고 정리한 내용입니다.
ES6에서 추가된 생성자가 symbol 원시 값을 반환하는 내장 객체
충돌 위험이 없는 유일한객체의 프로퍼티 키(property key)를 만들기 위함이다.
아래 예시를 보자
const list = [1, 2, 3];
for (let i = 0; i < list.length; i++) {
console.log(list[i]);
}
for (const a of list) console.log(a);
// 리스트를 순회하고 출력되는 로그는 같다.
const set = new Set([1, 2, 3]);
for (const a of set) console.log(a);
// 위 셋을 순회하고 출력되는 로그도 같다.
for (let i = 0; i < set.length; i++) {
console.log(set[i]); // undefined
}
// 하지만 set[i] = undefined
Array, Set, Map은 Symbol.iterator로 속성키를 사용한다.
const arr = [1, 2, 3];
console.log(arr[Symbol.iterator]);
// f values() { ... } > 함수
arr[Symbol.iterator] = null;
for (const a of arr) console.log(a);
// arr의 Symbol을 null로 초기화 하면 Error 발생
// arr is not iterable
arr
은 Symbol.iterator
을 가지고 있기때문에 이터러블이다.arr[Symbol.iterator]();
> 이터레이터이터러블/이터레이트 프로토콜 예시
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}
iterator.next(); // { value: undefined, done: true}
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
const keys = map.keys(); // value가 map의 key인 iterator
const values = map.values() // value가 map의 value인 iterator
for (const a of values) console.log(a); // 1 > 2 > 3
// values로 만든 이터레이터(MapIterator {1, 2, 3})를
// 심볼 이터레이터로 실행(next();) 했기때문에 value를 출력할 수 있다.
iterable변수는 [Symbol.iterator]라는 키를 가지고 있으며 이를 실행했을 때 이터레이터를 반환
const iterable = {
[Symbol.iterator]() {
let i = 3;
return {
next() {
return i == 0 ? {done: true} : {value: i--, done: false};
},
// *well-formed iterable
[Symbol.iterator]() {
return this;
}
}
}
};
const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
iterator.next();
for (const a of arr) console.log(a);
// 2, 3 만 출력
[Symbol.iterator]() {
return this;
}
// 위 속성을 추가하여
console.log(iterable[Symbol.iterator]() == iterable) // true
오픈소스뿐만 아니라 JS가 사용되고있는 환경인 브라우저에서 사용할 수 있는
webAPIs에 구현되어있는 많은 값들이 이터러블/이터레이터 프로토콜을 따르고있다
const all = document.querySelectorAll('*');
for (const a of all) console.log(a);
// 순회가 가능하다
// 따라서,
let iterator = all[Symbol.iterator]();
console.log(iterator.next()); // <html></html>
console.log(iterator.next()); // <head></head>
console.log(iterator.next()); // <script></script>
...
전개 연산자도 이터러블/이터레이터 프로토콜을 따르고 있는 값들을 펼치는 것이다.
const list = [1, 2];
list[Symbol.iterator] = null;
console.log([...list, ...[1, 2, 3]]);
// list Symbol을 null로 초기화 하면 Error 발생
// list is not iterable
Reference