WeakMap은 무엇일까? 간단하게 말하면, key를 Object로만 사용하는 Map이다. 물론 이렇게만 말한다면, Map의 하위 호환 처럼 보인다. 그렇다는 것은 이것은 무엇 때문에 생긴것일까?
WeakMap은 무엇이 약한 Map일까? 키에 대한 참조가 약한 Map이다. 키에 대한 참조가 약하다니 무슨 뜻일까?
Map은 key가 더 이상 접근이 불가능 하더라도, Map에는 값이 존재한다. 하지만 WeakMap은 가비지 컬렉션의 대상이 되어 가비지 컬렉터한테 걸리면 key를 참조 하지 못하는 데이터를 제거 한다.
예제를 보면 이와 같다.
let weakmap = new WeakMap()
let obj = {key: 'key'}
weakmap.set(obj, 'hello')
console.log(weakmap.get(obj)) // 'hello'
obj = null // obj가 가비지 컬렉션에 의해 제거됨
// weakMap {obj, 'hello'} 또한 가비지 컬렉션에 의해 제거된다.
let map = new Map()
let obj = {key: 'key'}
map.set(obj, 'hello')
console.log(map.get(obj)) // 'hello'
obj = null // obj가 가비지 컬렉션에 의해 제거됨
// map {obj, 'hello'} 제거 되지 않는다.
weakmap에는 데이터가 존재 하지 않는다. |
map에는 여전히 데이터가 존재한다. |
가비지 컬렉터가 실행 된 이후에 각각의 객체를 확인 해보면 위와 같이 확인 할 수 있다. 하지만, 가비지 컬렉터가 실행되지 않았다면, WeakMap을 이용 하더라도 아래처럼 확인이 되니, 주의하자.
접근 할 수 있는 key제거 되었지만, value가 남아있다. |
참고로 위처럼 한번이라도 개발자 콘솔에서 확인이 되면, 가비지 컬렉션의 대상이 되지 않는 듯 한다.
일단 가비지 컬렉터와 관련된 데이터 타입이니, 더 이상 접근이 불가능 한 값에 대해서 메모리 누수를 제어하기 위한 데이터 타입일 거라고 추측 할 수 있다.
정확히 생성된 이유는 솔직히 말 할 순 없다. 필요한 여러 이유가 있었을 것이고, 이런거 만들면 이런 코드들에 사용 할 수 있을 것 같은데? 이런식으로 만들어졌을 테니...
사용 예1
간단하게 특정 DOM들에 대해서 데이터를 저장 해야 하는 데이터가 있을 수 도 있을 것이다.
DOM은 나만 제어하는 값이 아니다. 특히나 요즘 처럼 프런트엔드 프레임워크를 일상적으로 사용 하는 상황이라면 더욱더 말이다. data-set뭐 이런걸로 해당 엘리먼트에 값을 넣어둘 수 있긴 하다만, 문자열로 표현 가능한 데이터만 보관이 가능하기도 하고, html에 붙기 때문에, DOM을 위한 데이터를 보관하기에는 제약이 좀 있다.
let weakMap = new WeakMap()
setTimeout(() => {
let div = document.createElement('div')
document.body.appendChild(div)
weakMap.set(div, {test: 'test'})
}, 0)
setTimeout(() => {
document.body.innerHTML = ''
}, 1000)
위는 서로 다른 방식으로 DOM을 제어하는 두개의 함수가 있는 경우를 예시로 만들어 보았다.
우연히 가비지 컬렉터가 도는 도중에 데이터가 확인 되었다. |
이 처럼 내가 작성한 코드 이외의 코드가 DOM을 제어하는 경우 사용 할 수 있다.
사용 예2
간단하게, 비용이 비싼 함수를 위하여 cache를 만들 때도 필요 할 수도 있다. 이래와 같이 같은 객체로 호출 할 때에는 같은 연산을 할 필요가 없으니, 받은 인자 값에 대해 결과를 저장하는 경우 말이다.
let cache = new WeakMap()
function expensiveOperation(obj) {
if (cache.has(obj)) {
return cache.get(obj)
}
let result = JSON.stringify(obj)
cache.set(obj, result)
return result
}
let testKey = {testKey: 'testKey'}
let testKey2 = {testKey: 'testKey2'}
expensiveOperation(testKey)
expensiveOperation(testKey2)
testKey = null
가비지 컬렉터가 정상적으로 실행이 된 후 cache를 확인하면 아래와 같다.
비싼 함수인 만큼 함수 실행 결과 값도 엄청 비싼 값일 수 있다. 이런 때에도 메모리를 아낄수 도 있다.
댓글
댓글 쓰기