[JS] Object 대신 Map을 사용해야 하는 이유

donguraemi·2023년 8월 18일
0
post-thumbnail

자바스크립트는 Object로 key-value 값을 갖는 자료 구조를 만들 수 있다. 하지만 자바스크립트에는 별도의 해시 자료 구조인 MapSet이 존재한다. MapSet이 존재하는 이유에 대해 알아보자.

Hash Table

해시 테이블은 key에 value를 매핑할 수 있는 자료구조다. 자바스크립트에서 해시 테이블은 Object, Map, Set이 있다.

해시 테이블은 key-value 형태의 자료구조다.


Object

객체를 생성하는 방법은 다음 두 가지다.

  • new 생성자 사용하기
let user = Object();
  • 중괄호 사용하기 (리터럴 방식)
let user = {};

자바스크립트에서 객체의 사용이 빈번하여 Object에 익숙할 것이기 때문에 별도의 설명 없이 코드를 작성하겠다.

// key: value
let user = {
  name: 'John',
  age: 30
};

// add property
user.isAdmin = true;

// delete property
delete user.age;

// <property> in <object>
console.log('name' in user); // true
console.log('grade' in user); // false

복수의 단어를 key로 사용하려는 경우, 따옴표로 묶어서 사용한다.

let user = {
  name: 'John',
  age: 30,
  'likes birds': true
};

💥 const를 사용했는데 왜 수정이 가능한 걸까?

const user = {
  name: 'John';
  ...
};
user.name = 'Alice';

객체는 const로 선언해도 수정이 가능하다. user의 값을 고정할 뿐, 그 내용은 고정하지 않기 때문이다. 따라서 user = ...를 전체적으로 수정할 때만 오류가 발생한다.

💥 대괄호 표기법이 존재하는 이유

console.log(user.likes birds); // Error
console.log(user['likes birds']); // John

점 표기법은 키가 유효한 변수 식별자인 경우에만 사용할 수 있다. 유효한 변수 식별자란 공백이 없고, 숫자로 시작하지 않으며 _$를 제외한 특수 문자가 없어야 한다.

하지만 대괄호 표기법은 키에 어떠한 문자가 있던지 상관없이 동작한다.

let key = 'name';
console.log(user.key); // undefined
console.log(user[key]); // John

이외에도 대괄호 표기법은 key에 변수를 사용할 수 있다.


Map

맵은 key가 있는 데이터를 저장한다는 점에서 객체(Object)와 유사하지만 다양한 자료형을 허용한다 는 점에서 차이가 있다.

let map = new Map(); // 맵 객체 생성

// map.set(key, value)
map.set('alice', 1);

// map.get(key)
console.log(map.get('alice')); // 1
console.log(map.get('bob')); // undefined

// map.has(key)
console.log(map.has('alice')); // true
console.log(map.has('bob')); // false

// map.delete(key)
map.delete('alice');

// map.clear()
map.clear();

// map.size
console.log(map.size); // 0

Map vs. Object

앞서 언급했듯이 Map은 키에 다양한 자료형을 허용한다는 점에서 Object와 차이가 있다. Object의 키는 문자열이나 Symbol만 가능하다.

let obj = { };
let user1 = {
    name: 'John',
    age: 30
};

let user2 = {
    name: 'Alice',
    age: 20
};

obj[user1] = 1;
obj[user2] = 2;

for(let key in obj) {
    console.log(`${key} : ${obj[key]}`);
}
/*
	[object Object] : 2
*/

객체의 키로 user1, user2를 저장했음에도 불구하고, 키값이 [object Object]로 변환되어 저장된다. 게다가 user1user2를 구분하지 못한다.

let map = new Map();

...
map.set(user1, 1);
map.set(user2, 2);

for(let key of map.keys()) {
    console.log(key);
}
/*
{ name: 'John', age: 30 }
{ name: 'Alice', age: 20 }
*/

반면, 맵을 사용하면 객체의 값이 유지된다.

💥 Map을 객체처럼 사용하기?
맵도 객체처럼 점 표기법, 대문자 표기법을 이용하여 프로퍼티를 설정할 수 있다. 하지만 이는 맵을 사용하는 올바른 방법이 아니다.

let map = new Map();

map['1'] = 1;
map['2'] = 2;

for(let key in map) {
    console.log(`${key} : ${map[key]}`);
}
/*
1 : 1
2 : 2
*/
console.log(map.keys()); // [Map Iterator] {  }

맵에 객체 문법을 사용하면 해당 key-value는 객체 문법을 통해서만 조회할 수 있다.

💥 Map은 주소값을 가리킬까?
자바스크립트에서 데이터 타입은 크게 두 가지로 분리된다.

  • Primitive : 값을 그대로 할당
    ex. Number, String, Boolean, null, undefined
  • Reference : 값이 저장된 주소값을 할당
    ex. Object, Array, Function, Map, Set
let obj1 = {
    name: 'John',
    age: 30,
    friends: ['Alice', 'Bob']
};

let obj2 = {
    name: 'John',
    age: 30,
    friends: ['Alice', 'Bob']
};

console.log(obj1 === obj2); // false

참조형 타입은 값이 저장된 주소값을 할당하기 때문에 서로 다른 두 객체의 내용이 같다하더라도 주소가 다르면 서로 다른 객체로 판단한다.

이제 Map에 저장되는 객체가 주소값을 가리키는지 확인해보자.

let map = new Map();
...
map.set(obj1, 1);
console.log(map.get(obj2)); // undefined

위의 코드는undefined를 출력한다. obj1obj2의 내용이 같아도 주소값을 참조하기 때문에 서로 다른 객체로 판단한다.

obj1.name = 'Alice';
console.log(map.get(obj1)); // 1

obj1의 프로퍼티를 변경해도 주소값을 가리키기 때문에 obj1에 해당하는 value 값을 반환한다.


참고자료
JAVASCRIPT.INFO : object
JAVASCRIPT.INFO : map & set

0개의 댓글