왜 Object 대신 Map을 사용해야할까?
배경
Object와 Map 모두 key-value 저장을 위한 자료구조인데 헷갈리는 부분이 있어서 정리해본다.
key 순서 차이
1.key값을 정수형으로 사용할 때
정수형 key -> 오름차순으로 정렬된다
1-1. Object const obj = {}; obj[100] = 'a'; obj[2] = 'b'; obj[7] = 'c'; console.log(Object.keys(obj)); // ['2', '7', '100'] ← 순서 뒤바뀜
1-2. Map const map = new Map(); map.set(100, 'a'); map.set(2, 'b'); map.set(7, 'c'); console.log([...map.keys()]); // [100, 2, 7] ← 그대로 유지
📌 참고
그런데 왜 오름차순으로 정렬이 되는 것 일까?
키 값이 정수이면 '배열처럼' 쓰이기 위해 특별 취급된다.
- js에서는 배열도 결국 객체이기 때문에, arr[0]같은 배열 접근도 내부적으로 obj['0']으로 작동
- 정수형 키는 배열처럼 동작하도록 일부러 오름차순 정렬되도록 설계된 것
const obj = {2: 'two', 1: 'one'}; console.log(Object.keys(obj)); // ['1', '2']
2. key값을 문자열로 사용할 때
문자열 key (정수아님) -> 삽입 순서 유지
2-1. Object const obj2 = {}; obj2['banana'] = 1; obj2['apple'] = 2; obj2['cherry'] = 3; console.log(Object.keys(obj2)); // ['banana', 'apple', 'cherry'] ← 순서 유지되는 듯?
2-2. Map const map2 = new Map(); map2.set('banana', 1); map2.set('apple', 2); map2.set('cherry', 3); console.log([...map2.keys()]); // ['banana', 'apple', 'cherry']
3. key값을 숫자+문자열로 사용할 떄
3-1. Object const obj3 = {}; obj3['3'] = 'three'; obj3['b'] = 'bee'; obj3['1'] = 'one'; obj3['a'] = 'ay'; console.log(Object.keys(obj3)); // ['1', '3', 'b', 'a'] ← 정수 먼저 정렬됨
3-2. Map const map3 = new Map(); map3.set('3', 'three'); map3.set('b', 'bee'); map3.set('1', 'one'); map3.set('a', 'ay'); console.log([...map3.keys()]); // ['3', 'b', '1', 'a'] ← 삽입 순서 그대로
순회 차이
1.Object ( 순회 불가능 )
const obj = {}; obj[100] = 'a'; obj[2] = 'b'; obj[7] = 'c'; // for...in으로 객체의 key 열거 (순회가 아님) for (const key in obj) { console.log(key); // 2,7,100 } // 키-값 쌍 반복 Object.entries(obj) // [['2','b'],['7','c'],['100','a']] // 키만 반복 Object.keys(obj); // ['2','7','100'] // 값만 반복 Object.values(obj); // ['a','b','c']
2. Map ( 순회 가능 )
const map = new Map(); map.set(100, 'a'); map.set(2, 'b'); map.set(7, 'c'); for (const [key, value] of map) { console.log(key, value); } // 100 'a' // 2 'b' // 7 'c' map.forEach((value,key,array)=>{ console.log(value,key,array); }); // a 100 Map(3) {100 => 'a', 2 => 'b', 7 => 'c'} // b 2 Map(3) {100 => 'a', 2 => 'b', 7 => 'c'} // c 7 Map(3) {100 => 'a', 2 => 'b', 7 => 'c'}
📌 참고
배열을 forEach로 순회하게 되면 Array.prototype.forEach()에 arr.forEach((element,index,array)=>{})이렇게 되어있는데
Map은 다르게 Map.prototype.forEach()은 map.forEach((value,key,map)=>{})으로 되어있다.
속도 차이
const N = 100,000; const keys = Array.from({ length: N }, (_, i) => `key${i}`); const obj = {}; keys.forEach((key, i) => { obj[key] = i; }); keys.forEach((key) => { const val = obj[key]; }); const map = new Map(); keys.forEach((key, i) => { map.set(key, i); }); keys.forEach((key) => { const val = map.get(key); });
| 테스트 | 실행 속도 (ops/s) | 오차 범위 | 비교 결과 |
| Map | 67 ops/s | ±5.72% | ✅ 가장 빠름 (기준) |
| Object | 61 ops/s | ±6.4% | 🔻 약 10.25% 느림 |
| 항목 | 의미 |
| ops/s | 초당 실행 횟수 (operations per second), 숫자가 클수록 빠르다 |
| ± 퍼센트 | 오차 범위 (statistical margin of error) |
| X% slower | 가장 빠른 테스트보다 몇 % 느린지 |
| Fastest | 이 테스트가 가장 빠른 성능을 기록했다는 뜻 |
📌 참고
JSBench.me에서 동일한 코드를 여러번 실행 하면 세부적인 숫자 차이는 있지만 결론은 Map이 조금 더 빠르다고 나온다.
참고
https://tc39.es/ecma262/#sec-array.prototype.foreach
https://tc39.es/ecma262/#sec-map.prototype.foreach
