데이터 검색 성능은 웹 애플리케이션의 사용자 경험에 직접적인 영향을 미치는 중요한 요소입니다. 특히 데이터 목록이 많아질수록 검색 알고리즘의 효율성이 더욱 중요해집니다. 이 글에서는 JavaScript에서 배열의 includes() 메서드와 Set 객체의 has() 메서드의 차이점을 살펴보고, 실제 사용 사례를 통해 성능 최적화 방법을 알아보겠습니다.
✅ 배열과 Set의 기본 개념
☑️ 배열(Array)
배열은 JavaScript에서 가장 기본적인 자료구조로, 여러 값을 순서대로 저장합니다. 배열에서 특정 값을 찾을 때는 주로 includes() 메서드를 사용합니다.
const favorites = ["BTC", "ETH", "XRP"];
console.log(favorites.includes("BTC")); // true
console.log(favorites.includes("SOL")); // false
☑️ Set 객체
Set은 ES6에서 도입된 자료구조로, 중복되지 않는 값들의 집합을 저장합니다. Set의 주요 특징은 해시 테이블 기반으로 동작하여 값 검색이 매우 빠르다는 점입니다.
const favSet = new Set(["BTC", "ETH", "XRP"]);
console.log(favSet.has("BTC")); // true
console.log(favSet.has("SOL")); // false
☑️ 시간 복잡도 비교
두 메서드이 가장 큰 차이점은 시간 복잡도에 있습니다.
메서드 | 시간 복잡도 | 설명 |
Array.includes() | O(n) | 배열의 모든 요소를 순차적으로 검사해야 함 |
Set.has() | O(1) | 해시 테이블 기반으로 상수 시간에 검색 가능 |
☑️ 실습
금융 데이터를 표시하는 웹 애플리케이션을 예로 들어보겠습니다. 사용자가 즐켜찾기로 등록한 암호 화폐 목록과 전체 암호 화폐 목록이 있다고 가정해 보겠습니다.
☑️ 비효율적 방식: Array.includes()
// 사용자가 즐겨찾기한 암호화폐 심볼 목록
const favorites = ["BTC", "ETH", "XRP", /* ... 더 많은 항목 */];
// 전체 암호화폐 목록에서 즐겨찾기 여부 확인
const facorites = mockAssets.filter(asset => favorites.includes(asset.symbol));
🍂 이 방식의 문제점:
- 각 asset 마다 favorites 배열 전체를 순회해야 함
- mockAssets가 500개, favorites가 100개 라면 최대 50,000번의 비교 연산이 발생
- 목록이 많을수록 성능이 급격히 저하됨
☑️ 최적화된 방식: Set.has()
// 사용자가 즐겨찾기한 암호화폐 심볼 목록을 Set으로 변환
const favSet = new Set(favorites);
// 전체 암호화폐 목록에서 즐겨찾기 여부 확인
const favoriteCryptos = mockAssets.filter(asset => favSet.has(asset.symbol));
🌱 이 방식의 장점:
- 각 asset마다 상수 시간 O(1)에 검색 가능
- Set은 한번만 생성하고, 이후 모든 검색은 즉시 수행됨
- 데이터가 많아질수록 성능 차이가 극대화됨
☑️ 실제 구현 예시
// 상태 관리에서 즐겨찾기 목록 가져오기
const favorites = useAssetStore((state) => state.favorites);
// Set으로 변환하여 검색 최적화
const favSet = new Set(favorites);
// 각 자산을 순회하며 즐겨찾기 여부 확인
return mockAssets.map(asset => {
const isFav = favSet.has(asset.symbol);
return (
<div key={asset.symbol}>
{asset.name} ({asset.symbol})
<span>{isFav ? '★' : '☆'}</span>
</div>
);
});
☑️ 성능 측정 결과
실제 성능 차이를 확인하기 위해 간단한 벤치마크를 실행해보았습니다.
// 테스트 데이터 준비
const largeArray = Array.from({ length: 10000 }, (_, i) => `item-${i}`);
const searchItems = Array.from({ length: 1000 }, (_, i) => `item-${i * 5}`);
const searchSet = new Set(searchItems);
// 배열 방식 성능 측정
console.time('Array includes');
const arrayResults = largeArray.filter(item => searchItems.includes(item));
console.timeEnd('Array includes');
// Set 방식 성능 측정
console.time('Set has');
const setResults = largeArray.filter(item => searchSet.has(item));
console.timeEnd('Set has');
실행 결과:
- Array includes: 약 320ms
- Set has: 약 5ms
이는 Set을 사용한 방식이 배열을 사용한 방식보다 약 64배 빠르다는 것을 보여줍니다!
✅ 결론
- 소규모 데이터의 경우 두 방식의 성능 차이는 미미하므로 가독성과 편의성을 우선할 수 있습니다.
- 대규모 데이터 또는 빈번한 검색이 필요한 경우:
- 원본 데이터는 배열로 관리
- 검색이 필요할 때 Set으로 변환하여 사용하는 것이 최적의 방법입니다.
- 실시간 필터링이나 대량 렌더링이 필요한 UI 컴포넌트에서는 Set 사용을 적극 고려해야 합니다.
'인턴' 카테고리의 다른 글
[ Troubleshooting🛠️ ] sticky 포지션과 overflow: hidden 충돌 해결하기 (0) | 2025.04.21 |
---|---|
Zustand 완전 정복 가이드 (0) | 2025.04.15 |
[ Troubleshooting🛠️ ] Tailwind 다크모드 깜박임 현상 해결하기 (0) | 2025.04.14 |
자주 쓰는 Docker 명령어 정리 (0) | 2025.04.14 |
[ Troubleshooting🛠️ ] eslint 규칙 변경으로 인한 빌드 에러 (0) | 2025.04.11 |