배열 생성 방법별 성능 비교
const arr1 = [...new Array(100)].map((v, i) => {return i + 1})
const arr2 = Array.from({length: 100}, (v, i) => {return i + 1})
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