
함수형 프로그래밍뿐만 아니라 실무에서도 리스트 형태를 순회하는 것은 중요하다. 자바스크립트의 순회 방법은 ES6가 되면서 리스트 순회하는 방법이 바뀌게 되었다.
const li = [1,2,3,4]
for ( var i = 0 ; i < li.length; i++){
console.log(li[i]);
}
ES6이전에는 리스트를 순회하는 방법이 위와 같았다. for 반복문을 이용해서 각 요소를 index값을 이용해서 접근하는 방식이었다. 이는 유사배열을 순회할 때도 마찬가지였다.
for (const a of li){
console.log(a);
}
ES6부터는 for...of문을 지원하게 되었다. 실제 동작은 변한 것이 없지만, 문법적으로 간결하고, 이전 형태보다 선언적으로 바뀌게 되었다. 이전의 모습을 명령적으로 i를 0부터 li의 길이만큼 하나씩 증가시키면서 li의 i번째 요소를 출력하라 라는 식이었지만, for...of문은 그런 명령적인 느낌이 없어진 것을 볼 수 있다.
즉, 내부적으로 순회하는 방식을 추상화 했다는 것을 알 수 있다.
자바스크립트에는 for...in과 for...of가 있다. 이 둘의 차이는 단순히 영어 in과 of의 차이가 아니다.
먼저 for...in을 보자.
const obj = {
a: 1,
b: 2,
}
const arr = [1,2]
for(const i in obj){
console.log(i);
}
// a b
for(const i in arr){
console.log(i);
}
// 0 1
위 코드를 보면 객체를 순회할 때 i의 값은 객체의 프로퍼티의 키가 된다. 배열을 보자. 배열을 순회한다는 것은 보통 배열의 요소들에 순차적으로 접근하기 위함이다. 그런데 위 코드의 결과를 보면, 배열의 요소가 아닌 이상한 값이 출력된다. 저 값은 바로 배열의 인덱스 값이다.
다시 돌아가보면, 자바스크립트에서는 거의 모든 것이 객체라고 했었다. 그렇다. 배열도 객체다.
객체가 무엇인가 따져보자면, 객체는 키와 값의 쌍으로 프로퍼티를 가질 수 있고, 메소드를 가질 수 있다. 이런 측면에서 봤을 때 배열은 배열만의 메소드가 있고 (ex map, filter...), 우리가 잘 아는 length 프로퍼티를 가지고 있다. 즉, 배열도 객체라는 것이다.
그런데 객체는 프로퍼티를 가질 때 키와 값의 한 쌍으로 갖는다고 했다. 그렇다면, 배열의 요소 값일테고, 키는 무엇일까? 맞다. 바로 인덱스다. 실제로 배열을 펼쳐보면,

위 사진처럼 키를 인덱스로 값을 배열의 요소로 갖는 객체를 확인할 수 있다. 물론 그 안에 length라는 키도 있다.
이처럼 for...in문의 경우는 객체를 순회하면서 키를 받는 방식이다. 하지만, for...of는 다르다.
const arr = [1,2,3]
for (const a of arr){
console.log(a);
}
// 1 2 3
const obj = {
a: 1,
b: 2,
}
for (const a of obj){
console.log(a);
}
위 코드를 실행했을 때 배열의 경우는 그 요소들이 순차적으로 잘 출력된다는 것을 알 수 있다.
하지만 객체의 경우는 다르다.

위의 사진처럼 객체를 for...of로 순회하려고 하면 오류가 발생한다. 즉, 이 반복문은 객체를 순회하기 위한 반복문이 아니다.
그렇다면 일반 for문과 for...of문의 차이는 무엇일까? for...of는 객체를 순회하기 위한 것이 아니라면 배열만을 순회하기 위한 것이 아닌가? 그러면 일반 for문과 코드가 간결한 것말고는 별차이가 없는 것이 아닌가?
이렇게 말하면 당연히 더 차이가 있다는 것을 눈치채고 있을 것이다. 그럼 그 차이에 대해 알아보자.
먼저 for문은 유사 배열의 순회가 가능하다. 유사 배열은 키를 인덱스로 갖고, length라는 프로퍼티를 가지고 있는 객체를 의미한다. 그 예시로는 문자열이 있을 수 있다.
우선 객체라는 것은 프로퍼티 접근 연산자를 통해 프로퍼티 값을 얻을 수 있다는 뜻이고, 그중 배열은 그 키가 인덱스로 이루어져 있기 때문에 []만을 이용해서 프로퍼티의 값에 접근하는 것이다. 이런 방식이 가능한 배열이 아닌 객체를 유사 배열이라고 한다.
const str = 'string'
for(let i = 0 ; i < str.length; i++){
console.log(str[i]);
}
// s t r i n g
str.length;
// 6
Array.isArray(str);
// false
위 코드에서 보듯 문자열을 담고 있는 str변수는 배열과 같이 []를 통해 각 요소에 접근할 수 있고, length라는 프로퍼티를 가지고 있지만, 마지막 줄에서 보듯이 배열인가를 물어보면 false를 얻게 된다.
위의 의미는 유사 배열은 배열이 아니라는 것이다. 즉, 배열이 가지고 있는 배열의 메소드를 유사배열은 사용하지 못한다. 물론 지금 하려는 과정에서는 중요하지 않지만, 이 특징을 기억하고 있어야 왜 함수형 프로그래밍이 좋은지 알 수 있을 것이다.
일단 for문으로 이런 유사 배열을 순회할 수 있다는 것을 알아두자. 그렇다면, 유사 배열을 만들어서 순회를 할 수 있지 않을까? 맞다.
const simArr ={
'0': 1,
'1': 2,
'2': 3,
length: 3
}
for(let i = 0; i<simArr.length;i++){
console.log(simArr[i]);
}
// 1 2 3
위에서 선언한 simArr은 유사배열이다. 그렇기 때문에 for문을 이용한 일반 배열의 순회처럼 순회할 수 있다.
그렇다면 for...of문은 뭐가 다를까?
const arr = [1,2,3]
for(const a of arr){
console.log(a);
}
for(const a of simArr){
console.log(a);
}

위 사진은 위의 코드의 결과이다. 일반 배열은 for...of문을 돌 수 있지만, 유사 배열은 불가능하다.
오류 내용을 읽어보자. simArr이 이터러블이 아니라는 소리를 한다. 그렇다. for...of문은 사실 배열의 형태를 하고 있는 값을 순회하기 위한 것이 아니라, 이터러블을 순회하는 방식이다.
정리하자면 다음과 같다.
for문 : 명령적인 방식의 순회, 배열을 순회하는 방식으로 유사 배열을 순회할 수 있다.for..in: 객체를 순회하기 위한 문, 배열을 순회하게 되면 인덱스를 가지고 for문처럼 접근하는 수밖에 없다.for...of: 이터러블을 순회하기 위한 문, 유사 배열은 이터러블이 아니면 순회할 수 없다.위 정리에서 유사 배열이 이터러블이 아니면 순회할 수 없다고 했다. 그 이유는 유사 배열이면서 이터러블일 수 있기 때문이다. 그 예시가 문자열이다
const str = 'string'
for(const a of str){
console.log(a);
}
// s t r i n g
일반 배열을 순회하는 것처럼 문자열도 for..of문을 이용해 순회가 가능하다. 문자열은 유사배열이면서 이터러블이기 때문이다.