reduce와 스프레드 연산자(Spread syntax)를 함께 사용하는 걸 피해라
자바스크립트의 reduce는 매우 강력한 내장 함수이다. 배열의 덧셈, 곱셈 등의 연산에 많이 사용되지만 자유도가 높아서 map, filter 등의 함수도 모두 reduce로 구현할 수 있다. 하지만 reduce 사용 시 주의해야 할 점이 있다. 그건 바로 reduce와 스프레드 연산자를 함께 쓰지 않는 것이다. 다음 코드를 예로 들어보자.
const arr = [
{ id: "ironman", name: "Tony Stark" },
{ id: "hulk", name: "Bruce Banner" },
{ id: "blackwidow", name: "Natasha Romanoff" },
];
const superheroes1 = arr.reduce(
(acc, item) => ({
...acc,
[item.id]: [item.name],
}),
{}
);
console.log("superheroes1", superheroes1);
const superheroes2 = {};
arr.forEach((o) => (superheroes2[o.id] = o.name));
console.log("superheroes2", superheroes2);
위의 코드는 arr 배열을 id를 키값으로 한 오브젝트로 변환하는 예이다. superheroes1, superheroes2의 결과는 같다. 그럼 성능은 어떨까? 아래 결과를 보면 superheroes2가 superheroes1보다 훨씬 빠르게 나온다.
왜 이런 결과가 나오는 걸까?
이유는 스프레드 연산자에 있다. TC39 Proposal에서 스프레드 연산자를 보면 내부적으로 Object.asign()처럼 동작한다. 스프레드 연산자는 Object.asign()의 Syntex sugar라고 할 수 있다.
// Shallow Clone (excluding prototype)
let aClone = { ...a };
// Desugars into:
let aClone = Object.assign({}, a);
그럼 Object.assign()는 어떻게 동작할까? MDN과 TC39를 보면 객체를 순환하면서 복사하고 있다. 즉, 시간복잡도가 O(N)이다.
다시 reduce 코드로 돌아가보자
const superheroes1 = arr.reduce(
(acc, item) => ({
...acc,
[item.id]: [item.name],
}),
{}
);
reduce는 배열에 대해 N번 실행된다. (시간복잡도 O(N))
그리고 reduce의 callback을 단계별로 단순화해보면
// 첫번째 순회
acc -> {}
{ ...acc, ironman: 'Tony Stark' } // 복사 필요 없음
// 두번째 순회
acc -> { ironman: 'Tony Stark' }
{ ...acc, hulk: 'Bruce Banner' } // 한번 복사
// would be copied to the new object
// 세번째 순회
acc -> { ironman: 'Tony Stark', hulk: 'Bruce Banner' }
{ ...acc, blackwidow: 'Natasha Romanoff' } // 두번 복사
// ... 복사 반복
조건에 따라서 다르겠지만 callback에서 O(N)이 발생한다. reduce의 O(N)만큼 O(N)이 수행되는 것이기 때문에 O(N^2)만큼 수행된다고 볼 수 있다. 그래서 두 번째 예제 for문 O(N) 보다 느린 것이다. 빅오 표기법에서 알 수 있듯이 데이터가 커질수록 시간복잡도가 급격하게 커진다.
당장 데이터가 체감을 할 수 없을 만큼 작다고 하더라도 확장성을 고려한다면 reduce와 스프레드 연산자를 함께 사용하는 패턴을 피해야 할 것이다.
참고 : Why using object spread with reduce probably a bad idea
'개발' 카테고리의 다른 글
console.log 시간 출력 (0) | 2022.09.30 |
---|---|
axios 캐시 적용 및 원리 (by axios-extensions) (0) | 2022.09.24 |
html2canvas는 어떻게 캔버스를 그릴까 (0) | 2022.09.18 |
자바스크립트로 PDF 내보내기 (0) | 2022.09.16 |
크록포드 스타일 자바스크립트 오브젝트 (Crokford Style Javascript Ojbect) (0) | 2022.09.07 |