가비지 컬렉터
: 자바스크립트 엔진은 도달 가능한 (추후 사용가능성이 있는) 값을 메모리에 유지
: 자료구조를 구성하는 요소도 자신이 속한 자료구조가 메모리에 남아있는 동안 대개 도달 가능한 값으로 취급되어
메모리에서 삭제되지 않음
: 객체의 프로퍼티나 배열의 요소, 맵이나 셋을 구성하는 요소들이 이에 해당
: 맵에서 객체를 키로 사용할 경우에도 맵이 메모리에 있는 한 객체도 메모리에 남음
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // 참조를 null로 덮어씀
// john을 나타내는 객체는 맵 안에 저장되어있습니다.
// map.keys()를 이용하면 해당 객체를 얻는 것도 가능합니다.
for(let obj of map.keys()){
alert(JSON.stringify(obj));
}
alert(map.size);
위크맵 (WeakMap)
: 키로 객체만을 사용해야하는 맵
: 위크맵의 키로 사용된 객체를 참조하는 것이 아무것도 없다면 해당 객체는 메모리와 위크맵에서 자동으로 삭제됨
: 맵과 달리 반복 작업과 keys(), values(), entries()를 지원하지 않음
: 동작 시점을 정확히 알 수 없는 가비지 컬렉션의 동작 방식으로 인해 위크맵의 요소를 파악하는 것이 불가능하며
지원하는 메서드가 제한적임. 때문에 키나 전체 값을 얻는 것이 불가능
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "ok"); //정상적으로 동작합니다(객체 키).
// 문자열("test")은 키로 사용할 수 없습니다.
weakMap.set("test", "Whoops"); // Error: Invalid value used as weak map key
- weakMap.get(key)
: 위크맵 키의 Value를 반환
- weakMap.set(key, value)
: 위크맵의 키에 값을 설정
- weakMap.delete(key)
: 위크맵의 키를 삭제
- weakMap.has(key)
: 위크맵에 주어진 요소가 존재하는지 여부를 판별해 반환
위크맵의 유스케이스 : 추가데이터
- 부차적인 데이터를 저장할 곳이 필요할 때
: 서드파티 라이브러리와 같은 외부 코드에 ‘속한’ 객체를 가지고 작업을 해야 한다고 가정할 때
이 객체에 데이터를 추가해줘야 하는데, 추가해 줄 데이터는 객체가 살아있는 동안에만 유효한 상황
이럴 때 위크맵을 사용
: 위크맵에 원하는 데이터를 저장하고, 키는 객체를 사용하면 됩니다.
이렇게 하면 객체가 가비지 컬렉션의 대상이 될 때, 데이터도 함께 사라지게 됨
weakMap.set(john, "비밀문서");
// john이 사망하면, 비밀문서는 자동으로 파기됩니다.
: 아래 예시의 경우 Map을 사용할 경우 john을 나타내는 객체는 가비지 컬렉션의 대상이 되어야 하는데
visitCountMap의 대상이기 때문에 삭제가 되지 않기 때문에 따로 삭제가 필요함
: 그러나 WeakMap을 사용할 경우 john 객체가 가비지 컬렉션의 대상이 되면 같이 삭제됨
// 📁 visitsCount.js
let visitsCountMap = new WeakMap(); // 위크맵에 사용자의 방문 횟수를 저장함
// 사용자가 방문하면 방문 횟수를 늘려줍니다.
function countUser(user) {
let count = visitsCountMap.get(user) || 0;
visitsCountMap.set(user, count + 1);
}
// 📁 main.js
let john = { name: "John" };
countUser(john); // John의 방문 횟수를 증가시킵니다.
// John의 방문 횟수를 셀 필요가 없어지면 아래와 같이 john을 null로 덮어씁니다.
john = null;
위크맵의 유스케이스 : 캐싱
- 캐싱
: 시간이 오래걸리는 작업의 결과를 저장해서 시간과 비용을 절약해주는 기법
: 동일한 함수를 여러 번 호출해야 할 때, 최초 호출 시 반환된 값을 어딘가에 저장해 놓았다가
그다음엔 함수를 호출하는 대신 저장된 값을 사용하는 게 캐싱의 실례
- 예시
: process(obj)를 여러 번 호출하면 최초 호출할 때만 연산이 수행되고, 그 이후엔 연산 결과를 cache에서 가져오는 예시
: 맵을 사용할 경우 객체가 필요 없어져도 cache를 수동으로 청소해 줘야함
: 맵을 위크맵으로 교체하면, 객체가 메모리에서 삭제될 때 캐시에 저장된 결과(함수 연산 결과)
역시 메모리에서 자동으로 삭제
// 📁 cache.js
let cache = new 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;
// 이 예시에선 맵을 사용한 예시처럼 cache.size를 사용할 수 없습니다.
// 하지만 obj가 가비지 컬렉션의 대상이 되므로, 캐싱된 데이터 역시 메모리에서 삭제될 겁니다.
// 삭제가 진행되면 cache엔 그 어떤 요소도 남아있지 않을겁니다.
위크셋 (WeakSet)
: 위크셋은 셋과 유사 하지만, 객체만 저장할 수 있으며 원시값은 저장할 수 없음
: 셋 안의 객체는 도달 가능할 때만 메모리에서 유지
: 셋과 마찬가지로 위크셋이 지원하는 메서드는 add, has, delete뿐
: size, keys()나 반복 작업 관련 메서드는 사용할 수 없음
: 위크맵과 유사하게 위크셋도 부차적인 데이터를 저장할 때 사용
: 다만 위크셋엔 위크맵처럼 복잡한 데이터를 저장하지 않음
: "예"나 “아니오” 같은 간단한 답변을 얻는 용도로 사용. 물론 위크셋에 저장되는 값들은 객체임
let visitedSet = new WeakSet();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
visitedSet.add(john); // John이 사이트를 방문합니다.
visitedSet.add(pete); // 이어서 Pete가 사이트를 방문합니다.
visitedSet.add(john); // 이어서 John이 다시 사이트를 방문합니다.
// visitedSet엔 두 명의 사용자가 저장될 겁니다.
// John의 방문 여부를 확인해보겠습니다.
alert(visitedSet.has(john)); // true
// Mary의 방문 여부를 확인해보겠습니다.
alert(visitedSet.has(mary)); // false
john = null;
// visitedSet에서 john을 나타내는 객체가 자동으로 삭제됩니다.
위크맵과 위크셋의 단점
: 위크맵과 위크셋의 가장 큰 단점은 반복 작업이 불가능하다는 점
: 위크맵이나 위크셋에 저장된 자료를 한 번에 얻는 게 불가능
: 이런 단점은 불편함을 초래하는 것 같아 보이지만, 위크맵과 위크셋을 이용해 할 수 있는 주요 작업을 방해하진 않음
: 위크맵과 위크셋은 객체와 함께 ‘추가’ 데이터를 저장하는 용도로 사용
Refference
'Programming > JavaScript' 카테고리의 다른 글
자바스크립트 - 구조 분해 할당 (0) | 2022.04.04 |
---|---|
모던 자바스크립트 (자료구조와 자료형) 3-9. JSON과 메서드 (0) | 2022.04.03 |
모던 자바스크립트 (자료구조와 자료형) 3-7. 배열 (0) | 2022.04.03 |
모던 자바스크립트 (자료구조와 자료형) 3-6. Date 객체와 날짜 (0) | 2022.04.03 |
모던 자바스크립트 (자료구조와 자료형) 3-5. 맵(map)과 셋(set) (0) | 2022.04.03 |