배경
ES6 이후 이터러블(iterable)이나 유사 배열 객체(array-like object)를 실제 배열로 변환하는 상황은 매우 흔합니다. 대표적으로 [...iterable](전개 구문, Spread Syntax)과 Array.from() 메서드를 사용합니다. 두 방식은 대부분의 경우 동일하게 동작하는 것처럼 보이지만, 동작 원리와 지원 범위에 명확한 차이가 있어 상황에 맞게 선택해야 합니다.
핵심 차이점
두 방식의 가장 큰 차이는 변환할 수 있는 소스 객체의 타입입니다.
전개 구문 (
[...iterable]) 오직 이터러블 프로토콜을 따르는, 즉Symbol.iterator속성을 가진 객체에만 사용할 수 있습니다.NodeList가 이터러블인 최신 브라우저 환경에서는 문제없이 동작하지만, 그렇지 않은 환경에서는TypeError가 발생합니다.Array.from()두 종류의 객체를 모두 배열로 변환할 수 있습니다.- 이터러블 객체
length속성과 인덱싱된 요소를 가진 유사 배열 객체
NodeList는 Symbol.iterator 구현 여부와 관계없이 항상 length 속성과 인덱스를 가지므로, Array.from()은 어떤 환경에서든 NodeList를 안정적으로 배열로 변환할 수 있습니다. 이런 이유로 호환성 측면에서 더 견고한 선택입니다.
실용적 관점에서의 비교
Array.from()은 선택적 두 번째 인자로 매핑 함수(map function)를 받을 수 있다는 중요한 장점이 있습니다.
예를 들어, 이터러블을 배열로 변환한 뒤 바로 각 요소에 특정 연산을 적용하고 싶을 때를 생각해 봅시다.
전개 구문 사용 시
[...iterable].map(item => doSomething(item))이 코드는 먼저 이터러블을 펼쳐 중간 배열을 생성하고, 그 다음map메서드를 통해 최종 결과 배열을 만듭니다. 즉, 두 단계를 거치며 중간 배열이 메모리에 잠시 할당됩니다.Array.from사용 시Array.from(iterable, item => doSomething(item))Array.from은 배열 생성과 매핑을 한 번의 순회로 처리합니다. 중간 배열을 만들지 않아 미세하지만 더 효율적이며, 코드가 더 직관적으로 읽힐 수 있습니다.
물론, 단순히 배열로 변환하기만 한다면 두 방식의 성능 차이는 거의 무시할 수 있는 수준이므로 코드 스타일이나 팀 컨벤션에 따라 선택해도 무방합니다.
결론
상황에 따른 권장 사용법은 다음과 같습니다.
- 전개 구문 (
[...]): 변환 대상이 이터러블임이 명확하고, 별도의 매핑 작업이 필요 없을 때 간결한 코드를 위해 사용합니다. Array.from(): 유사 배열 객체를 다루거나 구형 환경과의 호환성을 고려해야 할 때, 또는 배열 생성과 동시에 매핑을 적용하여 성능을 최적화하고 싶을 때 사용합니다.