
본 포스트는 인프런의 함수형 프로그래밍과 JavaScript ES6+ 강의(링크)를 듣고 정리한 내용입니다.
const list = [1, 2, 3];
for (var i = 0; i < list.length; i++) {
console.log(list[i]);
}
list.length라는 프로퍼티에 의존하고, 리스트 내부의 값을 숫자라는 key로 순회 하도록 i를 증가시키는 방식const list = [1, 2, 3];
for (const a of list) {
console.log(a);
}
Symbol.iterator
ES6에서 추가된 Symbol
Symbol.iterator는 어떤 객체의 키로 사용될 수 있다.
const arr = [1, 2, 3];
console.log(arr[Symbol.iterator]) //출력결과: ƒ values() { [native code] }
for (const a of arr) console.log(a);
//출력결과:
//1
//2
//3
array는 key값으로 배열의 내부 값에 접근 가능
만약 Symbol.iterator의 값을 null로 설정할 경우 순회가 되지 않는다.
arr[Symbol.iterator] = null;
for (const a of arr) console.log(a);
const set = new Set([1, 2, 3]);
console.log(set[Symbol.iterator]) //출력결과: ƒ values() { [native code] }
for (const a of set) console.log(a);
//출력결과:
//1
//2
//3
set은 key값으로 내부 값에 접근 불가능
for i++의 방식으로는 배열 순회가 불가능 => for of의 내부 구조는 for i++와는 다르다.const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
console.log(map[Symbol.iterator]) //출력결과: ƒ values() { [native code] }
for (const a of map) console.log(a);
//출력결과:
//(2) ['a', 1]
//(2) ['b', 2]
//(2) ['c', 3]
map도 key값으로 내부 값에 접근 불가능
이터러블: 이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값
Array Set Map 모두 iterable이다.이터레이터: { value, done } 객체를 리턴하는 next()를 가진 값
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}
done: true가 된다.이터러블/이터레이터 프로토콜: 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록한 규약
const arr = [1, 2, 3];
let iter1 = arr[Symbol.iterator]();
iter1.next();
for (const a of iter1) console.log(a);
//2
//3
let iter2 = arr[Symbol.iterator]();
iter2.next();
iter2.next();
for (const a of iter2) console.log(a);
//3
next()를 실행 하면 for...of의 순회가 하나씩 뒤로 밀린다.for...of는 이터러블한 객체의 이터레이터를 순회하며 실행된다.Set Map 도 동일하다. (이터러블/이터레이터 프로토콜의 규약을 따른다.)const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
map.keys(); //MapIterator {'a', 'b', 'c'}
var a = map.keys();
a.next(); //{value: 'a', done: false}
a.next(); //{value: 'b', done: false}
a.next(); //{value: 'c', done: false}
a.next(); //{value: undefined, done: true}
for (const a of map.keys()) console.log(a);
//a
//b
//c
for (const a of map.values()) console.log(a);
//1
//2
//3
for (const a of map.entries()) console.log(a);
//(2) ['a', 1]
//(2) ['b', 2]
//(2) ['c', 3]
map.keys() 라는 함수는 이터레이터를 리턴한다.
그리고 이 이터레이터를 실행하게 되면 value의 key만 남게 된다.
리턴된 이터레이터도 이터러블이다!!
for...of로 key값만 순회가 가능하다.value를 뽑는 values()와 내부의 key와 value를 entry로 뽑아주는 entries()라는 함수도 존재한다.
const iterable = {
[Symbol.iterator]() {
let i = 3;
return {
next() {
return i === 0 ? { done: true } : { value: i--, done: false };
},
};
},
};
let iterator = iterable[Symbol.iterator]();
// console.log(iterator.next()); //{ value: 3, done: false }
// console.log(iterator.next()); //{ value: 2, done: false }
// console.log(iterator.next()); //{ value: 1, done: false }
// console.log(iterator.next()); //{ done: true }
for (const a of iterable) {
console.log(a);
}
//3
//2
//1
for (const a of iterator) {
console.log(a);
}
//iterator is not iterable
iterable을 직접 구현해 봤다.for...of에 넣었을 때 iterator is not iterable에러가 발생한다.well-formed
이터레이터가 자기자신을 반환하는
Symbol.iterator를 가지고 있을때well-formed 이터레이터라고 한다.
Iterator이면서Iterable인 객체를 말한다.
non well-formedwell-formed이터러블이 진행된 지점을 기억하지 못해 처음부터 Restart 이터러블이 진행된 지점을 기억하고 그 지점부터 Restart
const iterable = {
[Symbol.iterator]() {
let i = 3;
return {
next() {
return i === 0 ? { done: true } : { value: i--, done: false };
},
[Symbol.iterator]() {
return this;
},
};
},
};
let iterator = iterable[Symbol.iterator]();
console.log(iterator[Symbol.iterator]() === iterator); //true
iterator.next();
for (const a of iterator) {
console.log(a);
}
//2
//1
well-formed로 다시 구현해 보았다Symbol.iterator를 가지고 있다.
ArraySetMap뿐만 아니라DOM도 이터러블/이터레이터 프로토콜 규약을 따른다.const all = document.querySelectorAll("*"); console.log(all[Symbol.iterator]); //ƒ values() { [native code] } console.log(all[Symbol.iterator]()); //Array Iterator {} let iter = all[Symbol.iterator](); console.log(iter.next()); //{value: html.focus-outline-visible, done: false} console.log(iter.next()); //{value: head, done: false} console.log(iter.next()); //{value: meta, done: false}
const a = [1, 2];
const map = new Map([
["a", 1],
["b", 2],
]);
const b = [...a, ...map];
console.log(b); //[ 1, 2, [ 'a', 1 ], [ 'b', 2 ] ]
for (const a of b) {
console.log(a);
}
//1
//2
//[ 'a', 1 ]
//[ 'b', 2 ]
전개 연산자로 다른 유형의 값을을 전개한 결과도 이터러블/이터레이터 프로토콜 규약을 따른다.