이터러블이란 반복 가능한 객체를 의미합니다.즉 요소를 하나씩 차례대로 접근할 수 있는 객체를 말합니다.
배열
const arr = [1, 2, 3];
for (const item of arr) {
console.log(item); // 1, 2, 3
}
문자열
const str = "hello";
for (const char of str) {
console.log(char); // h, e, l, l, o
}
{value : 값 , done : true/false} 형태의 이터레이터 객체를 리턴하는 next() 메서드를 가진 객체.next 메서드로 순활할 수 있는 객체입니다.
const arr = [1,2,3]; //arr는 그냥 평범한 배열
const iter = arr[Symbol.iterator]();
/*
문법 파헤치기 : key값을 문자열이 아닌 변수로 주기위해 arr[변수] 형태를 가진다.
위 사진에서 보듯이, Symbol.iterator 라는 key값을 가지고 value는 함수이다.
이를 접근해서 함수실행() 시키면 이터레이터 객체가 반환되어 iter에 담기게 된다.
*/
iter.next()
//>{value:1,done: false}
iter.next()
//>{value:2, done: false},
iter.next()
//{value:3, done: false}
iter.next()
//{value: undefined, done: true}
이터러블(iterable) : 위에서 설명한 바와 같이 메서드 Symbol.iterator가 구현된 객체.
유사 배열(array-like) : 인덱스와 length 프로퍼티가 있어서 배열처럼 보이는 객체.
우선 배열과 유사배열의 차이점을 알아보겠습니다.
var array = [1, 2, 3];
array; // [1, 2, 3]
var nodes = document.querySelectorAll('div'); // NodeList [div, div, div, div, div, ...]
var els = document.body.children; // HTMLCollection [noscript, link, div, script, ...]
위 예제에서는 els 와 nodes 가 유사배열이고 array가 배열입니다. 겉만 봐서는 잘 모르지만 Array.isArray메서드를 사용해서 뭐가 배열인지 확인해보겠습니다.
Array.isArray(array); // true
Array.isArray(nodes); // false
Array.isArray(els); // false
직접 배열 리터럴로 선언한 array만 배열입니다. nodes나 els처럼 []로 감싸져 있지만 배열이 아닌 이들을 유사배열이라고 합니다.
let arrayLike = { // 인덱스와 length프로퍼티가 있음 => 유사 배열
0: "Hello",
1: "World",
length: 2
};
for (let item of arrayLike) {} // Symbol.iterator가 없으므로 에러 발생
이터러블과 유사 배열은 배열이 아니기 떄문에 push,pop 등의 메서드를 지원하지 않습니다.
배열과 유사배열을 구분해야 하는 이유는, 유사배열의 경우 배열의 메서드를 쓸 수 없기 때문입니다.
어떻게 하면 이터러블과 유사 배열에 메서드를 적용할 수 있을까요 ?
Array.from은 이터러블이나 유사 배열을 받아 '진짜'Array를 만들어 줍니다.
let arrayLike = { //유사배열
0: "Hello",
1: "World",
length: 2
};
Array.from(arrayLike); // ["Hello", "World"]
let arr = Array.from(arrayLike); // ["Hello", "World"] 배열이 됨으로서 이터러블 객체도 된다.
for (let item of arr) {} // 1,2,3,4,5 (배열-문자열 형 변환이 제대로 동작합니다.)
맵과 셋은 독리된 자료형이지 객체나 배열이 아닙니다.
그럼에도 불구하고 for..of문과 동작하는 이유는 인덱스로 접근하는게 아닌 이터러블 프로토콜을 따르고 있기 때문입니다.
자체적으로 내장 forEach()메서드를 지원하기도 합니다.
const set = new Set([1,2,3])
for (cosnt a of set) console.log(a) // 1,2,3
const map = new Map([['a',1],['b',2],['c',3]]);
// Map(3) {"a" => 1, "b" => 2, "c" => 3}
const iter = map[Symbol.itertator](); // 심볼.이터레이터가 자체 내장되었기에 불러오기만 하면
iter.next();
// {value: Array(2), done: false}
for(const a of map)
console.log(a); // ['a',1],['b',2],['c',3]