MDN 에서 Map
은 Object
에 비해서 키-값 쌍의 빈번한 추가 및 제거가 일어날 때 성능이 좀 더 좋다고 나와있길래 두 객체의 성능 차이가 궁금하여 포스팅하게 되었다.
이 글은 Map과 Object의 모든 차이점에 대해 다루는 것이 아닌, 오직 성능 차이에만 집중해서 다룬다.Map
과 Object
의 삽입(set), 삭제(delete), 조회(get)의 속도 차이를 테스트를 통해 알아본다.
const len = 10_000_000;
const test = new Map();
function setTest() {
console.time("Map Set");
for (let i = 0; i < len; i++) {
test.set(i, i);
}
console.timeEnd("Map Set");
}
function getTest() {
console.time("Map Get");
for (let i = 0; i < test.size; i++) {
test.get(i);
}
console.timeEnd("Map Get");
}
function deleteTest() {
console.time("Map Delete");
for (let i = 0; i < test.size; i++) {
test.delete(i);
}
console.timeEnd("Map Delete");
}
setTest()
: test
객체에 개의 데이터를 삽입(set)한다.getTest()
: test
객체에 있는 개의 데이터를 조회(get)한다.deleteTest()
: test
객체에서 개의 데이터를 삭제(delete)한다.삽입, 조회, 삭제를 4사이클 실행해보자.
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
/*
Map Set: 1.726s
Map Get: 422.872ms
Map Delete: 417.62ms
Map Set: 982.507ms
Map Get: 431.394ms
Map Delete: 265.018ms
Map Set: 1.237s
Map Get: 392.827ms
Map Delete: 234.23ms
Map Set: 1.128s
Map Get: 535.67ms
Map Delete: 242.832ms
*/
두 번째 사이클에 삽입, 삭제 속도가 크게 줄어들었다가, 세 번째 사이클 부터는 약간 증가한다. 하지만 최적화가 이루어져 첫 번째 사이클보다는 삽입, 삭제의 속도가 더 빠르다.
만약 반복문에서 Map
객체의 size
속성 대신 len
변수를 사용할 경우 최적화가 이루어지지 않는 것인지 삽입, 삭제 속도가 빨라지지 않는다.
const len = 10_000_000;
const test = new Map();
function setTest() {
console.time("Map Set");
for (let i = 0; i < len; i++) {
test.set(i, i);
}
console.timeEnd("Map Set");
}
function getTest() {
console.time("Map Get");
for (let i = 0; i < len; i++) {
test.get(i);
}
console.timeEnd("Map Get");
}
function deleteTest() {
console.time("Map Delete");
for (let i = 0; i < len; i++) {
test.delete(i);
}
console.timeEnd("Map Delete");
}
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
/*
Map Set: 1.747s
Map Get: 445.897ms
Map Delete: 1.082s
Map Set: 1.611s
Map Get: 428.978ms
Map Delete: 1.074s
Map Set: 1.695s
Map Get: 386.608ms
Map Delete: 1.064s
Map Set: 1.683s
Map Get: 390.052ms
Map Delete: 977.108ms
*/
const len = 10_000_000;
const test = {};
function setTest() {
console.time("Object Set");
for (let i = 0; i < len; i++) {
test[i] = i;
}
console.timeEnd("Object Set");
}
function getTest() {
console.time("Object Get");
for (let i = 0; i < len; i++) {
test[i];
}
console.timeEnd("Object Get");
}
function deleteTest() {
console.time("Object Delete");
for (let i = 0; i < len; i++) {
delete test[i];
}
console.timeEnd("Object Delete");
}
삽입, 조회, 삭제를 4사이클 실행해보자.
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
/*
Object Set: 206.636ms
Object Get: 10.581ms
Object Delete: 343.207ms
Object Set: 47.889ms
Object Get: 8.863ms
Object Delete: 460.919ms
Object Set: 767.949ms
Object Get: 10.762ms
Object Delete: 450.853ms
Object Set: 754.043ms
Object Get: 12.036ms
Object Delete: 442.485ms
*/
Map 객체와 마찬가지로 두 번째 사이클에서는 삽입 속도가 현저히 줄어든 걸 볼 수 있다. 하지만 세번째 사이클부터는 첫번째 사이클보다 속도가 느려지는 것이 Map 객체와 다르다.
Object 를 사용했을 때 삽입, 삭제, 조회의 속도 자체는 더 빠른 모습을 확인할 수 있다. 하지만 객체의 길이가 고정된 것이 아니라 동적으로 변경되고 삭제나 조회 작업이 객체의 길이에 의존할 경우 객체의 길이를 구하는 로직을 추가해야된다. 추가된 로직을 고려하면 다음과 같다.
const test = {};
function setTest() {
const len = 10_000_000;
console.time("Object Set");
for (let i = 0; i < len; i++) {
test[i] = i;
}
console.timeEnd("Object Set");
}
function getTest() {
console.time("Object Get");
const len = Object.keys(test).length; // 객체의 길이 구하기
for (let i = 0; i < len; i++) {
test[i];
}
console.timeEnd("Object Get");
}
function deleteTest() {
console.time("Object Delete");
const len = Object.keys(test).length; // 객체의 길이 구하기
for (let i = 0; i < len; i++) {
delete test[i];
}
console.timeEnd("Object Delete");
}
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
setTest();
getTest();
deleteTest();
/*
Object Set: 204.993ms
Object Get: 1.099s
Object Delete: 1.401s
Object Set: 47.024ms
Object Get: 1.124s
Object Delete: 1.494s
Object Set: 733.109ms
Object Get: 1.232s
Object Delete: 1.442s
Object Set: 729.083ms
Object Get: 985.013ms
Object Delete: 1.705s
*/
getTest
와 deleteTest
에 객체의 길이를 구하는 로직이 추가되었다. 객체의 길이를 구하는 로직은 의 시간복잡도를 갖기 때문에 이만큼에 시간이 더 소요된다. 따라서 조회와 삭제의 시간이 급격히 늘어난 것을 확인할 수 있다.
size
속성을 이용하여 의 시간복잡도로 객체의 길이를 구할 수 있다.Object
보다 속도가 더 느리다.Map
보다 빠르다.Map
과 Object
중 선택 시 여러 고려사항이 있겠지만, 성능적인 측면에서는 다음과 같이 요약할 수 있을 것 같다.
삽입, 삭제, 조회 시 객체의 길이를 구해야 할 경우 Map
을 고려해볼 수 있다. 하지만 그게 아니라면 높은 확률로 Object
가 더 빠를 것이다.