대부분의 경우 "for...in" 루프보다 일반적인 'for' 루프를 사용하는 것이 더 안전합니다. 그 이유는 "for...in" 루프는 인덱스(index)를 반환하면서, 중간에 비어 있는 인덱스가 있어도 이를 건너뛰고 아무런 알림 없이 지나가기 때문입니다. 반면 일반 'for' 루프는 값(value)을 출력하고, 비어 있는 인덱스에는 'undefined' 값이 표시되므로 개발자가 코드를 작성할 때 데이터 구조를 정확히 파악할 수 있어 혼란을 겪지 않습니다.
문법(Syntax)
1. for...in 루프
for (var x in array) {
// 코드
};위 코드는 "for...in" 루프의 기본 문법입니다. 변수 x에는 배열의 인덱스 문자열이 순서대로 할당됩니다.
2. 일반 for 루프
for (var i = 0; i < array.length; i++) {
// 코드
};위 코드는 일반적인 'for' 루프의 기본 문법입니다. 인덱스를 직접 제어하며 배열의 모든 위치를 빠짐없이 순회합니다.
예제 1: for...in 루프의 동작
다음 예제에서 배열 "num"은 처음에 5개의 요소(인덱스 0~4)만 가지고 있습니다. 이후 인덱스 7에 새로운 값을 추가하면, "for...in" 루프는 비어 있는 인덱스(5와 6)에 대해 아무런 언급 없이 실제로 값이 존재하는 인덱스만 연속적으로 실행합니다. 이러한 동작은 일반 'for' 루프와 다르며, 개발자에게 혼란을 줄 수 있습니다.
<html>
<body>
<script>
var num = [1,2,3,4,5];
num[7] = 7;
for (var x in num) {
document.write(x);
document.write("</br>");
}
</script>
</body>
</html>출력 결과
0 1 2 3 4 7
출력 결과를 보면 인덱스 5와 6은 완전히 생략된 채 0부터 4까지, 그리고 곧바로 7만 출력되었습니다. 즉, 배열에 빈 공간(hole)이 존재한다는 사실 자체가 감춰집니다.
예제 2: 일반 for 루프의 동작
다음 예제에서는 "for...in" 루프와 달리 일반 'for' 루프가 인덱스가 아닌 값을 출력합니다. 또한 비어 있는 인덱스(5와 6)에는 undefined 값이 그대로 표시되므로, 배열에 빈 자리가 있다는 것을 명확하게 알 수 있습니다.
<html>
<body>
<script>
var num = [1,2,3,4,5];
num[7] = 7;
for (var i = 0; i < num.length; i++) {
document.write(num[i]);
document.write("</br>");
}
</script>
</body>
</html>출력 결과
1 2 3 4 5 undefined undefined 7
추가로 알아두어야 할 점
"for...in" 루프가 배열 반복에 적합하지 않은 이유는 위와 같은 인덱스 누락 문제 외에도 몇 가지가 더 있습니다.
- 프로토타입 체인 순회: for...in은 객체의 상속된 열거 가능한 속성까지 함께 순회합니다. 따라서 Array.prototype에 커스텀 속성이 추가되어 있으면 의도하지 않은 값까지 출력될 수 있습니다.
- 순서 미보장: for...in은 속성을 탐색하는 순서를 보장하지 않으므로, 순서가 중요한 배열 반복에는 부적합합니다.
- 문자열 타입 인덱스: for...in이 반환하는 인덱스는 숫자가 아닌 문자열이므로, 산술 연산 등에서 예상치 못한 동작을 유발할 수 있습니다.
결론적으로 배열을 반복할 때는 일반 'for' 루프를 사용하는 것이 가장 안전하고 명확합니다. 최신 JavaScript 환경에서는 희소 배열(sparse array)의 빈 자리를 undefined로 처리해 주는 forEach(), map() 같은 배열 메서드나 ES6의 for...of 루프를 활용하는 것도 좋은 대안입니다.