필자는 한밭대학교 무선통신 소프트웨어 연구실 Wisoft에서 진행하는 HTML+CSS+JS 세미나 멘토를 담당하고 있다.

세미나 중 발표를 담당한 멘티가 DOM 에 대해 발표하면서, DOM 요소를 취득하는 메서드를 발표했다.
그러다 이 친구가 querySelector나 getElementsByClassName 등 의 메서드로 여러 DOM 요소를 저장하는 내용을 발표하다가, 책에서 나온 문구에 의문점을 제기했다.
배열이 비슷하고 배열처럼 사용할 수 있지만, 배열은 아니다.
뭐지 이게 배열인듯 배열아닌 배열같은 너 라는 소린가?
일단 이 질문을 받았을 때 바로 대답해 주려다 보니 반쪽짜리 대답을 해줘버렸다.
내 대답은 “유사 배열 객체에는 Array 자료형의 강력한 메서드들을 사용하지 못한다.” 였다.
그리고 Array 의 메서드들을 사용하려면 Array.from() 메서드를 통해 유사 배열 객체를 진짜 배열로 만들고 배열의 메서드를 쓰면 된다고 했다.
JS를 막 접한 멘티를 대상으로 설명하려다 보니 너무 두루뭉술한 설명이 나가버렸다.
세미나 이후 자세한 답변을 해주려고 조금 더 생각해보고 공부해서 정리해보자면 아래와 같다.
일단 이 답변을 이해하려면 이터러블에 대한 이해가 필요하다.
이터러블이란 이터레이션 프로토콜을 준수하는 순회 가능한 자료구조이다.
이런 이터러블이 되기 위해서는 이터레이션 프로토콜을 준수해야 한다는 소리이다.
이터레이션 프로토콜은 각각 이터러블 프로토콜과 이터레이터 프로토콜 로 나뉜다.
이터러블 프로토콜을 준수하는 방법은 2가지가 있다.
Symbol.iterator 를 내부적으로 직접 구현하거나, 프로토타입 체인을 통해 상속받은 Symbol.iterator를 호출하면 된다.
중요한게, Symbol.iterator()는 결국 함수다.
그러니까 반환값이 있다는 소리이다.
그럼 반환값이 뭐냐? 바로 “이터레이터 리절트 객체” 이다.
이터레이터 리절트 객체는 next 메서드를 소유하며, next 메서드를 호출하면 이터러블을 순회하면서 value 와 done 프로퍼티를 가진다.
이 next 메서드를 호출하면 이터러블을 순차적으로 순회하면서 결과를 나타내는거다.
const arr = [1, 2, 3];
console.log(arr);
console.log(arr[Symbol.iterator]);
const iterator = array[Symbol.iterator]();
console.log(iterator);
// 이터레이터의 next 메서드를 호출해 이터레이터 리절트 객체가 반환되었다.
// 이터레이터 리절트 객체는 이터러블을 순차적으로 순회하며 결과를 나타낸다.
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
위 코드를 이해해보자.
배열 리터럴을 사용해 arr 을 선언했다.
즉, arr은 이제 배열이다.
console.log(arr[Symbol.iterator]); 를 해보면 아래와 같은 결과가 나온다.

저 f values() { [native code] } 는 간단히 생각해서 arr의 이터레이터를 나타내는 내장 함수라고 생각하면 된다.
어쨌든 중요한건, arr 안에는 Symbol.iterator 가 있다는 거다!
arr는 이미 배열이므로, Array.prototype 의 프로토타입 체인 상에 Symbol.iterator() 를 상속받아 호출하는 것 같다. 직접 구현한게 아니라는 소리다!
okay okay 이제 이터러블이 뭔지 좀 알겠다 !
왜 지금까지 신나게 이터러블을 설명했는가?
바로 유사 배열 객체와 배열의 가장 큰 차이점은
이터러블이냐, 아니냐.
이기 때문이다!
이터러블이 아니라면, 배열 메서드 뿐 아니라 ES6의 강력한 기능들을 사용하지 못하게 된다.
스프레드 문법이나 for … of , 구조분해 할당, 제너레이터 등의 기능등의 할당을 사용할 수 없다는것이다!
그럼 우린 불편한 concat 을 사용하거나 **for(let i = 0; i < 5; i++)** 등의 짓거리를 계속 해야한다.
ㅠ_ㅠ
유사 배열 객체가 뭐죠? 배열과의 차이는요?
라는 대답에 꽤나 길게 대답을 해 봤다.
처음에 했던 대답이 “배열 메서드 못써요, 쓰려면 배열로 만드셈”. 이었다면
이 글을 읽고 나서는 이렇게 대답할 수 있겠다.
유사 배열 객체는 배열과 유사한 구조를 가진 객체에요.
가장 큰 차이로는, 유사배열 객체는 내부적으로 Symbol.itertor를 구현하지 않거나,
프로토타입 체인 상에서 상속받아서 호출하지 않아서 이터러블이 아니라는 거에요.
이터러블이 아니니까 배열 메서드를 사용하지 못해요. 더불어 다른 ES6+ 의 문법도 사용하지 못합니다.
그럼 유사 배열 객체에서 배열 메서드를 쓰거나, ES6+의 문법을 사용하려면 어떻게 하냐구요?
간단한 방법은 배열로 만들면 됩니다. Array.from() 메서드를 쓰면 배열로 만들어서 메서드를 쓸 수 있겠죠.
근데 제 생각에 이렇게 해결하는건 소가 뒷걸음질치다 쥐 잡은 격 이라고 생각해요.
어쩌다 보니 배열 메서드를 사용할 수 있게 된거죠.
정확한 해결법은, Symbol.iterator를 구현해서 이터러블로 만든 뒤 배열 메서드와 ES6+의 문법을 사용하는
게 올바른 방법 아닐까요?
라는 내용의 소설 추천좀.
찐공부네요.