프론트 공부/JavaScript와 모던 JS

JavaScript로 배열 다루기 : for in 문은 배열에서 쓰지 마라?

홍구리당당 2023. 10. 19. 17:52

for in 문을 배열에서 쓰면 안되는 이유.

필자는 보통 배열의 인덱스를 가지고 활용할 때 for in문을 쓰지만, for in 은 정확히 말하자면 해당 객체의 '프로퍼티 속성' 을 가져온다. js에서는 배열의 인덱스를 자동으로 프로퍼티 네임이라 인식하기 때문에 for in을 배열에 활용하면 인덱스가 나오는 것이다.

근데 사실 for in을 배열에 활용하면 여러 문제가 생길 수 있다. 아래 코드를 보자.

// 어떻게 출력될까?

const arr = ["a","b","c","d"];
for (let i in arr){
    console.log(i);
}

배열의 인덱스 값을 출력하니 0 1 2 3 4가 출력될거라 예상하겠지만, 사실 이렇게 출력된다.


(띠용...)

왜냐하면, for in문은 대상이 상속받은 속성까지도 순회하기 때문이다. 배열이라는 자료형은 기본적으로 프로퍼티로 isArray, compact, each, contains, copy... 등의 속성을 상속받는다. 즉, for in으로 프로퍼티를 순회하면 배열 내부 원소의 프로퍼티 뿐만 아니라 배열의 상속받은 속성까지도 출력된다.

그렇다면 for in으로 작성한 아래 코드는 작동할까?

const arr = [1, 2, 3, 4];
let sum = 0;
for (let i in arr){
    sum += arr[i];
}
console.log(sum);

당연히 에러가 난다. 숫자가 아닌 값들까지 더하려 하니 그렇다.

근데 vs code에서 실행해보면 에러가 나지 않는다 ㅋㅋㅋ

이 무슨 일??! vs code에서 실행하면 isArray나 compact 같은 배열 기본 속성은 출력되지 않고, 딱 인덱스만 출력되고 인덱스의 값들만 계산이 돼서 내가 원하는대로 다 실행이 된다.

왜 실행 환경마다 이렇게 달라지는 걸까, 하고 알아봤더니... 브라우저마다, 그리고 페이지의 설정값마다 함수가 달라지면서 이렇게 결과가 다르게 나올 수 있다는 것이다.

실제로 네이버 웹페이지에서 f12로 개발자 도구 열어서 해당 코드를 실행하면 잘 돌아간다.

결론. 구버전 브라우저나, 설정값이 다른 곳에서는 for in을 사용할 시 문제가 발생할 수 있다! 여러 사이트에서 테스트해봤는데 tistory 에서만 에러가 나더라. Deprecated as of 10.6.0. initHighlightingOnLoad() is deprecated. Use highlightAll() instead. 에러가 뜨는 사이트 특징인듯 하다.

안정적으로 코드를 짜려면 그냥 arr.length 값을 가져와 일반 for문을 쓰는 것이 좋다.

이 뿐만 아니라 for in문을 쓰면 임의의 순서로 인덱스에 접근할 수 있다. 특정 순서에 따라 인덱스를 반환하는 것을 보장할 수 없다는 뜻이다.

(MDN 문서. https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in)

for (let i =0;i<arr.length;i++) ... 코드는 배열의 길이를 정하고 그만큼 loop를 도는 것에 반해, for in은 객체의 속성을 찾기 때문에 반복 도중 배열 안에 원소를 추가하거나 삭제할 때 (배열의 길이가 가변할 때) 모든 element를 방문하지 못할 수도 있다.

이런 이유로, for in 문을 배열에서 사용하는 것은 조금 무리가 있다.

객체 내부 프로퍼티를 순서 신경 쓰지 않고 접근할 때에 사용하는 것이 낫다. 순서가 중요한 배열에서는 그냥 일반 for문, for of문, 혹은 forEach나 map 같은 내부 메소드를 사용하자.