자바스크립트는
Object
로 key-value 값을 갖는 자료 구조를 만들 수 있다. 하지만 자바스크립트에는 별도의 해시 자료 구조인Map
과Set
이 존재한다.Map
과Set
이 존재하는 이유에 대해 알아보자.
해시 테이블은 key에 value를 매핑할 수 있는 자료구조다. 자바스크립트에서 해시 테이블은 Object
, Map
, Set
이 있다.
해시 테이블은 key-value 형태의 자료구조다.
객체를 생성하는 방법은 다음 두 가지다.
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에 변수를 사용할 수 있다.
맵은 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
은 키에 다양한 자료형을 허용한다는 점에서 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]
로 변환되어 저장된다. 게다가 user1
과 user2
를 구분하지 못한다.
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은 주소값을 가리킬까?
자바스크립트에서 데이터 타입은 크게 두 가지로 분리된다.
Number
, String
, Boolean
, null
, undefined
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
를 출력한다. obj1
과 obj2
의 내용이 같아도 주소값을 참조하기 때문에 서로 다른 객체로 판단한다.
obj1.name = 'Alice';
console.log(map.get(obj1)); // 1
obj1
의 프로퍼티를 변경해도 주소값을 가리키기 때문에 obj1
에 해당하는 value 값을 반환한다.