📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[JavaScript] 객체와 배열을 닮은 ES6 Map, Set 객체 이해하기

Map 객체

Map 객체는 자바스크립트의 객체와 동일하게 'key-value' 값의 한 쌍으로 이루어진 집합이다.

우리가 알던 객체와는 다르게 메서드를 이용해서 객체의 프로퍼티에 접근한다.

 

사용 방법

const maps = new Map(); // Map 객체 생성

maps.set('name', 'shawn');
maps.set(123, 456);
maps.set(true, 'true');

maps.get('name'); // 'shawn'
maps.has('name'); // true
maps.delete(123); // true
maps.size(); // 2
maps.clear();

- map.set(key, value) : Map 객체에 key와 value값을 넣어준다. 이 때, 객체와 크게 다른 점이 있는데 key 값에 문자열만 가능했던 객체와는 달리 Map에서는 숫자형, 불린형 등 문자형 외에도 다양한 타입을 key 값으로써 설정할 수 있다.

- map.get(key) : 특정 key 값에 할당된 value 값을 조회한다.

- map.has(key) : 특정 key 값이 Map 안에 있는 지 확인하며, 값으로 boolean을 반환한다.

- map.delete(key) : 특정 key 값의 프로퍼티를 삭제한다.

- map.size() : 현재 Map 객체의 length 값을 조회한다.

- map.clear() : Map 객체를 초기화한다.

 

이외에도 다양한 메서드가 있으며, Map은 이렇게 우리가 알던 객체처럼 대괄호[ ]를 통해 프로퍼티에 접근하는 게 아니라 메서드를 이용해서 프로퍼티에 접근한다.

 

기존 객체의 형태는 {name: 'shawn', age: 10, country: 'korea'} 이런 식으로 생겼다면, Map 객체는 {['name', 'shawn'], ['age', 10], ['country', 'korea']} 이런 식으로 배열마냥 대괄호로 묶여져있는 것을 볼 수 있다.

 

for (let v of maps) {
    console.log(v); // [key, value], [key, value] …
}

일반 객체는 for~in만 가능했었지만, Map은 for~of도 가능하다. key-value 한 쌍이 배열로 감싸져서 반환된다.

몇 가지 부분만 빼면 사실상 Map은 우리가 알던 객체와 다름없다. 그러면 그냥 객체를 쓰면 되는 게 아닌가 싶지만, Map만이 가지는 고유한 특성 때문에 이따금씩 쓰이기는 한다. 특히 알고리즘 문제를 풀거나, 객체의 프로퍼티를 자주 변경해야할 때 자주 찾게 된다.

 

Set 객체

Map이 객체처럼 생긴 객체였다면, Set은 배열처럼 생긴 객체이다. Map과 동일하게 메서드를 통해 데이터에 접근할 수 있으며, 고유한 값을 가지는 객체이기 때문에 데이터를 중복없이 저장한다는 큰 특징을 가지고 있다.

 

사용 방법

const sets = new Set(); // Set 객체 생성

sets.add(1); // 1을 추가한다.
sets.delete(1); // 1을 제거한다.
sets.size; // 1
sets.clear(); // 초기화

new Set([1, 1, 2, 3]); // {1, 2, 3} => 배열을 넣어도 된다. (중복 제거)
new Set('AABBCC'); // {'ABC'} => 문자열을 넣어도 된다. (중복 제거)
new Set([{a: 1, b: 2, c: 3}]); // 배열로 감싼 객체를 넣어도 된다.

- set.add() : 값을 추가한다.

- set.delete() : 값을 삭제한다.

- set.size : 값의 크기를 조회한다.

- set.clear() : 객체를 초기화한다.

 

Set 객체를 만들 때, 위처럼 new Set()으로 Set 객체를 만들고 .add를 통해 값을 추가해줘도 되지만 기존에 있는 배열이나 객체를 Set 객체의 파라미터로 넣어서 만드는 것도 가능하다. (중복 제거용으로 배열 혹은 문자열을 넣을 수 있음)

Set 객체는 Map처럼 iterable한 특성을 가지기 때문에 for~of도 사용 가능하다. 반환되는 것은 배열과 동일하다.

 

집합으로 사용하기

Set 객체는 집합으로써 다룰 수도 있다. 대표적으로 합집합, 교집합, 차집합 등이 있다.

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [4, 5, 6, 7, 8];

// 합집합 (arr1 ∪ arr2)
function sum(fir, sec) {
    let first = new Set(fir);
    let second = new Set(sec);

    for (let v of second) {
        first.add(v);
    }
    for (let v of first) {
        first = [...first];
    }
    
    return first;
}

// result : [1, 2, 3, 4, 5, 6, 7, 8]

Set 객체는 중복 값은 제외한다는 특징이 있기 때문에 합집합은 add 메서드를 통해 쉽게 구할 수 있다.

 

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [4, 5, 6, 7, 8];

// 교집합 (arr1 ∩ arr2)
function intersect(fir, sec) {
    let first = new Set(fir);
    let second = new Set(sec);
    let res = new Set();

    for (let v of second) {
        if (first.has(v)) res.add(v);
    }
    for (let v of res) {
        res = [...res];
    }
    return res;
}

// result : [4, 5]

Set 객체의 has() 메서드를 통해 해당 값이 객체에 있는지 확인하고, 만약 있다면 res에 add하도록 하였다.

교집합 역시 Set의 메서드만을 이용해서 쉽게 구할 수 있다.

 

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [4, 5, 6, 7, 8];

// 차집합 (arr1 - arr2)
function minus(fir, sec) {
    let first = new Set(fir);
    let second = new Set(sec);
    let res = new Set();

    for (let v of first) {
        if (!second.has(v)) res.add(v);
    }
    for (let v of res) {
        res = [...res];
    }
    return res;
}

// result : [1, 2, 3]

차집합은 교집합의 조건을 반대로 해주었다. fir 배열 기준 sec 배열 안에 있는 값과 다른 경우 res에 add하도록 하였다.

 

1. Map은 객체와 닮은 객체로, {[key, value], [key, value], ...} 형태로 구성되어 있음.
2. Set은 배열과 닮은 객체로, {1, 2, 3, 4, 5, ...} 형태로 구성되어 있음.
3. 둘 다 기존의 객체나 배열처럼 대괄호([ ])나 점(.)을 통해 프로퍼티에 접근하는 게 아닌 메서드로 접근 가능함.
4. Map과 Set은 모두 iterable해서 for~of문을 사용할 수 있음.
5. Set은 중복 값을 가지지 않아서, 중복 제외할 때 사용하면 특히 좋음.
6. Set은 집합으로 쓰일 수 있으며 합집합, 교집합, 차집합 등 다양한 계산이 가능.