Array.prototype.includes vs indexOf 성능 비교
배경
레거시 코드를 리팩토링하면서 배열 내 값 존재 여부를 확인하는 로직들을 정리하게 됐다. 기존에는 indexOf를 사용했는데, ES6의 includes로 바꾸면 가독성이 더 좋아진다.
// 기존
if (roles.indexOf('admin') !== -1) {
// ...
}
// 변경 후
if (roles.includes('admin')) {
// ...
}
코드는 확실히 깔끔해졌는데, 성능 차이가 있는지 확인이 필요했다.
벤치마크
const arr = Array.from({ length: 10000 }, (_, i) => i);
const target = 9999;
console.time('indexOf');
for (let i = 0; i < 100000; i++) {
arr.indexOf(target) !== -1;
}
console.timeEnd('indexOf');
console.time('includes');
for (let i = 0; i < 100000; i++) {
arr.includes(target);
}
console.timeEnd('includes');
Node 8.11에서 테스트한 결과, 두 메서드의 성능 차이는 거의 없었다. 오히려 includes가 미세하게 빠른 경우도 있었다.
NaN 처리 차이
벤치마크보다 중요한 차이점을 발견했다.
const arr = [1, 2, NaN];
arr.indexOf(NaN); // -1
arr.includes(NaN); // true
indexOf는 NaN을 찾지 못하지만 includes는 정확히 찾는다. 이 부분 때문에라도 includes를 사용하는 게 맞다고 판단했다.
결론
성능 차이는 무시할 수준이고, 가독성과 정확성 면에서 includes가 우위에 있다. 팀 컨벤션에 includes 사용을 추가했고, 기존 코드도 점진적으로 마이그레이션하기로 했다. 다만 IE11 지원이 필요한 프로젝트에서는 polyfill이 필요하다.