Map, Set / WeakMap, WeakSet

100pearlcent·2021년 9월 7일
0

JavaScript

목록 보기
10/22
post-thumbnail

Map

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

Map 주요 메서드 & 프로퍼티

  • new Map() : 맵을 만든다
  • map.set(key, value) : key를 이용해 value를 저장
  • map.get(key) : key에 해당하는 값을 반환. key가 없으면undefined 반환
  • map.has(key) : key가 존재하면 true, 존재하지 않으면 false 반환
  • map.delete(key) : key에 해당하는 값 삭제
  • map.clear() : 맵 안의 모든 요소 제거
  • map.size : 요소의 개수 반환
let map = new Map();

map.set('1', 'str1'); // 문자형 key
map.set(1, 'num1'); // 숫자형 key
map.set(true, 'bool1'); // 불린형 key

// 객체는 key를 문자형으로 변환한다
// Mapdms key의 타입을 변환시키지 않고 그대로 유지한다

map[key]는 Map을 쓰는 바른 방법이 아니다
map[key] = 2로 값을 설정하는 것 처럼map[key]를 사용하는 방법은 map을 일반 객체처럼 취급하게 되므로 여러 제약이 생긴다 👉 map 사용 시에는 전용 메서드인 set, get을 사용한다

Map은 key로 객체를 허용한다

let jinju = {name: 'Jinju'};

// 고객의 방문 횟수를 세보기
let visitsCountMap = new Map();

// jinju를 map의 key로 사용
visitsCountMap.set(jinju, 123);

alert(visitsCountMap.get(jinju)); // 123

Map이 key를 비교하는 방식

Map은 SameValueZero 알고리즘을 사용해서 값의 등가 여부를 확인한다.
SameValueZero 알고리즘은 일치 연산자 ===와 거의 유사하지만, NaNNaN을 같다고 취급하는 것에서 일치 연산자와 차이가 있다.
👉 맵에선 NaN도 key로 쓸 수 있다

Chaining

map.set 호출 시 마다 맵 자신이 반환 👉 이를 이용하여 map.set 을 chaining

map.set('1', 'str1')
	.set(1, 'num1')
	.set(true, 'bool1')

Map은 삽입 순서를 기억한다

값이 삽입된 순서대로 순회를 실시한다. 객체가 프로퍼티 순서를 기억하지 못하는 것과는 다르다.

Set

중복을 허용하지 않는 값을 모아놓은 컬렉션, key가 없는 값이 저장된다.

Set 주요 메서드

  • new Set(iterable) : Set을 만듦. iterable 객체를 전달받으면(대개 배열) 그 안의 값을 복사해 Set에 넣어줌
  • set.add(value) : 값을 추가하고 Set 자신을 반환
  • set.delete(value) : 값 제거하고 호출 시점에 Set 내에 값이 있어서 제거에 성공하여 true, 없으면 false를 반환
  • set.has(value) : Set 내에 값 존재하면 true, 아니면 false 반환
  • set.clear() : Set을 비움
  • set.size : Set에 몇 개의 값이 있는지 카운트
// 방문자가 여러 번 방문해도 중복해서 기록하지 않으려 할 때 
let set = new Set();

let john = { name: 'John' };
let pete = { name: 'Pete' };
let mary = { name: 'mary' };

set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(pete);

// Set에는 중복저장이 되지 않는다
alert(set.size); // 3

for (let user of set) {
	alert(user.name); // John, Pete, Mary 순으로 출력
}

WeakMap & WeakSet

JavaScript 엔진은 도달 가능한 (그리고 추후 사용될 가능성이 있는)값을 메모리에 유지한다

// 아래 객체는 jinju라는 참조를 통해 접근할 수 있다
let jinju = { name: 'Jinju' };

// 그런데 참조를 null로 덮어쓰면 위 객체에 더 이상 도달 불가능하므로 객체가 메모리에서 삭제된다
jinju = null;

자료구조를 구성하는 요소도 자신이 속한 자료구조가 메모리에 남아있는 동안 대개 도달 가능한 값으로 취급되어 메모리에서 삭제되지 않는다.
객체의 프로퍼티나 배열의 요소, 맵이나 셋을 구성하는 요소들이 이에 해당한다.

let jinju = { name: 'Jinju' };

let arr = [ jinju ];

jinju = null;	// 참조를 null로 덮어 씀

// jinju를 나타내는 객체는 배열의 요소이기 때문에 가비지 컬렉터의 대상이 되지 않는다
// arr[0]을 이용해서 해당 객체를 얻을 수도 있다
alert(JSON.stringify(arr[0]);

WeakMap

map과 weakmap의 첫 번째 차이는 weakmap의 key가 반드시 객체여야 한다는 점이다
원시값은 위크맵의 key가 될 수 없다

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, 'ok'); // 정상적으로 동작한다 (객체 key)
weakMap.set('test', 'notOk'); // Error: Invalid value used as weak map key

weakmap의 key로 사용된 객체를 참조하는 것이 아무것도 없다면 해당 객체는 메모리와 weakmap에서 자동으로 삭제된다

let jinju = { name: 'Jinju' };

let weakMap = new WeakMap();
weakMap.set(jinju, '...');

jinju = null; // 참조를 덮어씀

// jinju를 나타내는 객체는 이제 메모리에서 지워진다

jinju를 나타내는 객체는 오로지 weakmap의 key로만 사용되고 있으므로, 참조를 덮어쓰게 되면 이 객체는 위크맵과 메모리에서 자동으로 삭제된다.

map과 weakmap의 두 번째 차이는 weakmap은 반복 작업과 keys(), values(), entries()메서드를 지원하지 않는다는 점 👉 weakmap에서는 key나 값 전체를 얻는 것이 불가능하다

WeakMap 지원 메서드

  • weakMap.get(key)
  • weakMap.set(key, value)
  • weakMap.delete(key)
  • weakMap.has(key)

WeakMap 유스케이스: 추가 데이터

  • 부차적인 데이터를 저장할 곳이 필요할 때

e.g.) 서드파티 라이브러리처럼 외부 코드에 속한 객체를 가지고 작업해야하는 상황 > 이 객체에 데이터를 추가해야하는데 추가해 줄 데이터는 객체가 살아있는 동안에만 유효 > 이럴 때 weakmap을 활용

weakmap에 원하는 데이터를 저장하고, 이 때 key는 객체를 사용한다 👉 객체가 가비지 컬렉션의 대상이 될 때 데이터도 함께 사라지게 된다

weakMap.set(john, '비밀문서');
// john 사망 시, 비밀문서는 자동으로 파기

e.g.) 사용자의 방문횟수를 세어주는 코드. 관련 정보는 map에 저장하는데 map 요소의 key에는 특정 사용자를 나타내는 객체를, 값엔 해당 사용자의 방문 횟수를 저장한다.
특정 사용자의 정보를 저장할 필요가 없어지면 (= 가비지 컬렉션의 대상이 되면) 해당 사용자의 방문 횟수도 저장할 필요가 없어진다

Map을 활용했을 때

let visitsCountMap = new Map(); // map에 사용자 방문횟수 저장

function countUser(user) {
	let count = visitsCountMap.get(user) || 0;
  	visitsCountMap.set(user, count + 1);
}

let john = { name: 'John' };

countUser(john); // John의 방문횟수를 증가시킴

// John의 방문 횟수를 셀 필요가 없어지면 아래와 같이 john을 null로 덮어씀
john = null;

john을 나타내는 객체는 가비지 컬렉션의 대상이 되어야하는데, visitsCountMap의 key로 사용되고 있어서 메모리에서 삭제되지 않는다

특정 사용자를 나타내는 객체가 메모리에서 사라지면 해당 객체에 대한 정보도 손수 지워줘야 하는 문제

👉 weakmap을 활용해서 예방할 수 있다

let visitsCountMap = new WeakMap(); // weakmap에 사용자의 방문 횟수를 저장

function countUser(user) {
	let count = visitsCountMap.get(user) || 0;
  	visitsCountMap.set(user, count + 1);
}

weakmap을 사용해서 사용자 방문횟수를 저장하면 visitsCountMap을 수동으로 청소해줄 필요가 없다 > john을 나타내는 객체가 도달 불가능 상태가 되면 자동으로 메모리에서 삭제되므로 weakmap의 key에 대응하는 값인 john의 방문 횟수도 자동으로 가비지 컬렉션의 대상이 된다

WeakMap 유스케이스: Caching

Caching❓: 시간이 오래 걸리는 작업의 결과를 저장해서 연산 시간과 비용을 절약하는 기법
e.g.) 동일한 함수를 여러 번 호출해야 할 때, 최초 호출 시 반환된 값을 어딘가 저장했다가 그 다음에 함수를 호출하는 대신 저장된 값을 사용

// 📁 cache.js
let cache = new WeakMap();

// 연산 수행 후 그 결과를 weakmap에 저장
function process(obj) {
if (!cache.has(obj)) {
	let result = obj;
  	/* 연 산 수 행 */
  	cache.set(obj, result);
	}
  return cache.get(obj);
}

// 📁 main.js
let obj = { /* 객 체 */ };

let result1 = process(obj);
let result2 = process(obj);

// 객체가 쓸모없어지면 아래와 같이 null로 덮어씀
obj = null;
  • obj가 가비지 컬렉션의 대상이 되므로, 캐싱된 데이터 역시 메모리에서 삭제될 것
  • 삭제가 진행되면 cache엔 어떤 요소도 남지 않음

WeakSet

  • set과의 차이점 - 객체만 저장할 수 있다, 원시값은 저장할 수 없다
  • set 안의 객체는 도달 가능할 때만 메모리에서 유지
  • add,has,delete를 사용가능하고 size, keys()나 반복작업 관련 메서드는 사용 불가
  • weakmap과 유사하게 부차적인 데이터를 저장할 때 사용
  • weakmap과는 달리 복잡한 데이터를 저장하지 않고 yes/no 같은 간단한 답변 얻는 용도
let visitedSet = new WeakSet();

let john = { name: 'John' };
let pete = { name: 'Pete' };
let mary = { name: 'Mary' };

visitedSet.add(john);
visitedSet.add(pete);
visitedSet.add(john);
// john 은 두 번 방문했지만
// visitedSet에는 두 명의 사용자가 저장된다

// John의 방문여부 확인하기
alert(visitedSet.has(john)); // true

// Mary의 방문여부 확인하기
alert(visitedSet.has(mary)); // false

// visitedSet에서 john을 나타내는 객체가 자동으로 삭제됨
john = null;

WeakMap, WeakSet 요약

  • 둘의 가장 큰 단점은 반복 작업이 불가능하다는 점

  • 주 용도는 객체와 함께 '추가'데이터를 저장하는데 쓰임

  • weakmap은 map과 유사한 컬렉션이고, weakmap을 구성하는 요소의 key는 오직 객체만 가능하고 key로 사용된 객체가 메모리에서 삭제되면 이에 대응하는 값까지 삭제된다

  • weakSet은 set과 유사한 컬렉션이고, 객체만 저장할 수 있다. weakset에 저장된 객체가 도달 불가능한 상태가 되면 해당 객체는 메모리에서 삭제된다

0개의 댓글