심심한 개발자의 취미생활

배열 생성 방법별 성능 비교

// 코드 A - spread + map
const arr1 = [...new Array(100)].map((v, i) => {return i + 1})

// 코드 B - Array.from
const arr2 = Array.from({length: 100}, (v, i) => {return i + 1})

// 코드 C - 순수 for 루프
const arr3 = []
for(let i = 1; i <= 100; i++) {
    arr.push(i)
}
항목 코드 A (spread + map) 코드 B (Array.from()) 코드 C (for loop)
성능 순위 최하 중간 상위
메모리 할당 빈배열 할당 -> map 시 새 배열 할당(이중할당) 배열 크기 한번에 할당, 생성 push 마다 내부 버퍼 관리
호환성 ES6+ ES6+ 상관 없음
사용 예시 단순 상수 값 채우기 등 특수한 경우(내용이 모두 같은 경우 등) 가독성, 타입 안정성 중시와 적당한 성능 확보시 성능이 최우선인 대용량 처리 영역

성능 비교

코드 A - spread + map

  • new Array(100)으로 빈 슬롯만 있는 배열을 만든 뒤, spread로 실제 undefined 요소가 있는 배열로 복사한 다음 map을 또 한 번 순회 하므로 가장 느립니다.
  • 요소 개수가 많을 때 성능 저하기 뚜렷해집니다.

코드 B - Array.from

  • 내부에서 배열 생성과 동시에 매핑 콜백을 실행하므로, new Array + map 처럼 "배열 생성 -> map 순회"의 두 단계가 아니라 한번에 처리합니다.
  • map보다는 빠르고, 순수 루프 보다는 약간 느린 중간 수준 성능을 보입니다.

코드 C - 순수 for 루프

  • 콜백 호출 오버헤드가 전혀 없으므로 세 가지 중 가장 빠릅니다.
  • 요소 개수가 많아 질수록 map-계열보다 더 우수한 성능을 보입니다.

메모리 할당

코드 A - spread + map

  • 빈 배열 -> spread 복사로 실제 요소 배열 할당 -> map 결과 배열 또 할당 -> 총 두번 배열을 만듦

코드 B - Array.from

  • length 기반으로 한 번만 배열 크기로 잡고, 콜백으로 바로 값을 채워 넣음

코드 C - 순수 for 루프

  • push 호출 시 내부 버퍼 재할당이 일어날 수 있지만, V8등 최신 엔진은 적절히 예측 및 최적화하여 큰 문제가 되지 않습니다.

가독성 & 유연성

코드 A - spread + map

  • 매우 간결하지만, "새 Array -> spread -> map" 조합이 직관적이지 않아 협업시 오해 가능

코드 B - Array.from

  • length 명시와 동시에 값 채움이라는 의도가 분명해 유지보수성과 가독성이 좋습니다.

코드 C - 순수 for 루프

  • 가장 직관적이고 "무슨 일이 일어나는지" 설명이 따로 필요 없지만, 반복문 + push가 장황하게 느껴질 수 있습니다.

호환성

코드 A, 코드 B

  • ES6 이상 가능 (..., Array.from 등)이 필요합니다

코드 C

  • 아주 구형 환경에서도 운영 가능