티스토리 뷰

Javascript

Map과 Set

mongoT 2020. 3. 1. 11:33

ES6에서 새롭게 추가된 데이터 구조 2개가 있다.

 

맵과 셋.

 

맵은 객체와 유사하고, 셋은 배열과 유사하다.

 

그 차이점이 뭘까?

 

Map

객체의 역할은 KEY와 VALUE를 연결하는 역할이다.

 

그런데 객체에는 몇 가지 한계들이 있다.

 

1. 프로토타입 체인 때문에 의도하지 않은 연결이 생길 수 있다.

2. 객체 안에 연결된 키와 값이 몇 개나 되는지 쉽게 알아낼 수 있는 방법이 없다.

3. 키는 반드시 문자열이나 심볼이어야 하므로 객체를 키로 써서 값과 연결할 수 없다..

4. 객체는 프로퍼티 순서를 보장하지 않는다.

 

맵은 위에서 나열한 4가지 문제점을 모두 극복해냈다.

 

코드를 보면서 확인해보자.

 

Map 인스턴스는 new연산자를 이용해서  만든다.

const u1 = {name: 'Cynthia'};
const u2 = {name: 'Jackson'};
const u3 = {name: 'Olive'};
const u4 = {name: 'James'};

const userRoles = new Map();

set()메서드를 이용해서 객체 Key에 value를 부여할 수 있다.

userRoles.set(u1, 'User');
userRoles.set(u2, 'User');
userRoles.set(u3, 'Admin');

console.log(userRoles); //  Map {
                        //   { name: 'Cynthia' } => 'User',
                        //   { name: 'Jackson' } => 'User',
                        //   { name: 'Olive' } => 'Admin'
                        // }

set() 메서드는 체인으로 연결 가능하다.

userRoles
    .set(u1, 'User')
    .set(u2, 'User')
    .set(u3, 'Admin');

생성자에 배열의 배열을 넘기는 형태로도 가능하다. (주의: 배열의 배열임.)

const userRoles = new Map([
    [u1, 'User'],
    [u2, 'User'],
    [u3, 'Admin']
]);

key에 해당하는 value를 알고 싶으면 get() 메서드를 사용한다.

userRoles.get(u2); // User

맵에 존재하는지 확인하는 has() 메서드도 있다.

userRoles.has(u1); // true
userRoles.has(u4); // false
userRoles.get(u4); // undefined

맵에 이미 존재하는 키에 set() 메서드를 호출하면 값이 교체가 된다.

userRoles.set(u1, 'Admin');
console.log(userRoles.get(u1)); // 'Admin'

keys() 메서드는 맵의 key를 반환, values()는 맵의 value를 반환 

for (let u of userRoles.keys()) {
  console.log(u);
}
// { name: 'Cynthia' }
// { name: 'Jackson' }
// { name: 'Olive' }

for (let r of userRoles.values()) {
  console.log(r);
}
// User
// User
// Admin

entries() 메서드는 맵의 기본 이터레이터다.

for (let [u, r] of userRoles.entries()) {
  console.log(u, r);
}
// { name: 'Cynthia' } User
// { name: 'Jackson' } User
// { name: 'Olive' } Admin

for (let [u, r] of userRoles) {
  console.log(u, r);
}
// { name: 'Cynthia' } User
// { name: 'Jackson' } User
// { name: 'Olive' } Admin

이 트러블 객체보다 배열이 필요하다면 확산 연산자(spread operator)

[...userRoles.values()]; // [ 'User', 'User', 'Admin' ]

맵의 요소를 지울 때는 delete() 메서드

userRoles.delete(u2);
console.log(userRoles.has(u2)); // false

맵의 요소를 모두 지울 때는 clear() 메서드, 크기는 size 프로퍼티

userRoles.clear();
console.log(userRoles.size); // 0

 

정리하자면 Map은

 

1. 프로토타입이란 게 Map에 존재하지 않으니 고려할 필요가 없다.

2. 객체 안의 몇 개의 프로퍼티가 존재하냐 => size

3. key에 object를 사용 가능하다.

4. 프로퍼티의 순서 => 이 트러블 iterable

 

단순히 key와 values를 연결할 목적이라면 객체보다는 맵이 훨씬 적합해보인다.

 

Set

셋은 중복을 허용하지 않는 데이터 집합이다.

위 예제에서 u1이라는 사용자에게 Admin이라는 역할과 User라는 역할을 부여할 때,

매번 그 때마다 부여한다고 생각해보면,

2개의 역할을 담기 위해 배열을 생각할 수 있을 것이다.

그러면 자연스럽게 내가 넣은 역할이 이미 있는지 체크하는 로직을 넣어야 할 것이다.

 

만약 배열을 사용한다면

 

const u1 = { name: "Cynthia" };
const userRoles = new Map();

// add role to user
function addRoleToUser(user, role) {
  if (userRoles.has(user)) {
    const roles = userRoles.get(u1);
    
    // check if the role already exists
    if (roles.some(elem => elem === role)) return;
    
    roles.push(role);
  } else {
    userRoles.set(user, [role]);
  }
}

addRoleToUser(u1, "User");
addRoleToUser(u1, "Admin");
addRoleToUser(u1, "Admin");
console.log(userRoles.get(u1)); // ['User', 'Admin']

직책이 2번 들어가는 것을 방지하기 위해서 

addRolteToUser라는 함수에 중간에 해당 직책이 이미 존재한는지 테스트를 해야한다. 

 

그렇지만 Set은 이미 있는지 확인할 필요가 없다. 이미 존재하면 아무일도 일어나지 않는다.

const u1 = { name: "Cynthia" };
const roles = new Set();

roles
    .add('User')
    .add('Admin');

roles.add('Admin');

console.log(roles); // Set { 'User', 'Admin' }

 

Set을 이용해서 함수를 수정하면

const u1 = { name: "Cynthia" };
const userRoles = new Map();

function addRoleToUser(user, role) {
  if (userRoles.has(user)) {
    const roles = userRoles.get(u1);
    roles.add(role);
    
  } else {
    const roles = new Set();
    roles.add(role);
    userRoles.set(user, roles);
  }
}

addRoleToUser(u1, "User");
addRoleToUser(u1, "Admin");
addRoleToUser(u1, "Admin");
console.log(userRoles.get(u1)); // ['User', 'Admin']

요소를 삭제하려면 delete 전체크기는 size프로퍼티.

roles
    .add('User')
    .add('Admin');

roles.delete('Admin');
console.log(roles.size);

 

참고문헌: Learning Javascript - 이선 브라운 Chatper 10 맵과 셋

 

 

'Javascript' 카테고리의 다른 글

다형성과 다중 상속  (0) 2020.03.01
객체프로퍼티 나열  (0) 2020.03.01
iterator 와 generator  (0) 2020.03.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함