Study Record

[JavaScript] 값의 집합 처리/조작하기 - Map, Set 본문

웹/Javascript

[JavaScript] 값의 집합 처리/조작하기 - Map, Set

초코초코초코 2025. 3. 11. 20:34
728x90

 

 

연상 배열 조작하기 - Map

Map 객체는 키/값 세트 이른바 연상 배열(해시)을 관리하기 위한 객체이다. 원래는 객체 리터럴로 연상 배열을 관리하는 것이 기본이었지만 ES2015에서 전용의 객체가 제공되었다.

 

 

 Map 객체 기본 사용 방법

let m = new Map();

// set(key, value) : 요소 추가하기
m.set('One', "AAA");
m.set('Two', 'BBB');
m.set('Three', 'CCC');
m.set('Four', 'DDD');

// 요소의 수
console.log(m.size);    // 4

// get(key) : key 에 상응하는 요소의 값 불러오기
console.log(m.get('Three'));    // CCC

// has(key) : 지정한 key가 존재하는지 판정한다.
console.log(m.has('Six'));    // false

// 키를 순서대로 취득
for(let key of m.keys()) {
    console.log(key);      // One Two Three Four
}

// 값을 순서대로 취득
for(let value of m.values()) {
    console.log(value);    // AAA BBB CCC DDD
}

// 키와 값을 순서대로 취득 (m 대신 m.enties() 도 가능)
for(let [key, value] of m) {
    console.log(`${key} : ${value}`);   // One : AAA , Two : BBB , Three : CCC , Four : DDD
}

// delete(key) : 지정한 키의 요소 삭제
m.delete("Three");
console.log(m);     // Map(3) { 'One' => 'AAA', 'Two' => 'BBB', 'Four' => 'DDD' }

// 모든 요소 삭제하기
m.clear();
console.log(m.size);    // 0

 

Map 객체 생성 예시)

let m1 = new Map([[1, 'T'], [2, 'G'], [3, 'F'], [4, 'A']]);
let m2 = new Map();

m2.set(1, 'T');
m2.set(2, 'G');
m2.set(3, 'F');
m2.set(4, 'A');

// 동일하다. Map(4) { 1 => 'T', 2 => 'G', 3 => 'F', 4 => 'A' }
console.log(m1);
console.log(m2);

 

 

 객체 리터럴과 Map 객체의 차이

 

㉮ Map 객체는 임의의 형으로 키를 설정할 수 있다.

객체 리터럴에서는 프로퍼티명을 키로 대체하고 있으니 키로 이용할 수 있는 것은 문자열뿐이다. Map 객체는 임의의 형을 키로 설정할 수 있다. Nan 도 가능하다.

 

㉯ Map의 사이즈를 취득할 수 있다.

객체 리터럴에서는 키/값의 개수를 취득할 수 없다. 따라서 for/in 루프 등으로 객체를 수동으로 카운트해야하지만 Map 에서는 size 프로퍼티를 사용하여 등록된 키/값의 사이즈를 취득할 수 있다.

 

㉰ 클린 맵 을 만들 수 있다.

객체 리터럴에서는 그 실체가 Object 객체이다. 따라서 Object 객체가 표준으로 준비하고 있는 프로퍼티(키)가 처음부터 존재한다. 빈 객체 리터럴을 작성한 시점임에도 이미 비어 있지 않은 상태인 것이다.

그러나 Map 객체는 전용의 객체이므로 완전히 빈 연상 배열을 생성할 수 있다. Object 객체에서도 create 메서드로 강제적으로 빈 객체를 생성할 수 있지만 클린 맵을 생성하고자 한다면 Map 객체를 이용하는 편이 좋다.

 

 

 키에 관한 주의점

 

특별한 NaN 이 특별하지 않다.

NaN 은 자기 자신과도 동등하지 않는 특별한 값이다.(NaN !== NaN) 그렇지만 Map 에서는 NaN === NaN 으로 간주한다.

var m = new Map([[NaN, 'hoge']]);

console.log(m.get(NaN));    // hoge

 

㉯ 키값이 객체 리터럴일 경우

var m = new Map([[{}, 'hoge']]);

console.log(m.get({}));    // undefined

undefined 값이 나오는 이유는 객체와 같은 참조형을 비교하는 경우 참조의 비교가 된다. 즉, 객체를 참조하고 있는 메모리의 주소값을 서로 비교하게 된다. 따라서 동일하게 빈 객체 리터럴({})을 비교하는 것처럼 보여도 서로 다른 메모리의 주소값을 가르키므로 동일하지 않다. 

 

올바른 예시)

var key = {};
var m = new Map([[key, 'hoge']]);

console.log(m.get(key));    // hoge

 

 

중복되지 않는 값의 집합 조직하기 - Set 객체

Set 객체는 중복되지 않은 값의 집합을 관리하기 위한 객체이다. Set 객체는 ES2015 부터 새롭게 도입된 객체이다. 키값이 따로 존재하지 않으며 값만 존재한다.

 

 

 Set 기본 동작

let s = new Set();

// 값 추가하기
s.add(10);
s.add(20);
s.add(5);

// 동일한 값은 무시한다.
s.add(10);

// 지정한 값의 유무 판정하기
console.log(s.has(20));     // true

// 요소의 수
console.log(s.size);   // 3

// 값을 순서대로 취득
for(let value of s.values()) {
    console.log(value);     // 10 20 5
}

for(let val of s) {
    console.log(val);     // 10 20 5
}

s.forEach(function(value, index, s) {
    console.log(value);   // 10 20 5
});

// 지정한 값 삭제하기
s.delete(5);
console.log(s);    // Set(2) {10, 20}

// 지정한 요소 모두 삭제하기 
s.clear();
console.log(s.size);    // 0

 

 

 NaN 객체의 비교

NaN 은 아무리 추가해도 서로 동일한 값으로 간주한다. 하지만 객체 리터럴은 참조형으로 차지하고 있는 메모리 값의 정보를 갖고 있는 참조형이므로 서로 다른 요소로 간주한다.

let s = new Set();

s.add(NaN);
s.add(NaN);

console.log(s.size);    // 1

let s2 = new Set();

s2.add({});
s2.add({});
s2.add({});

console.log(s2.size);    // 3
728x90