자바스크립트 엔진은 도달이 불가능한 값을 가비지 컬렉션을 통해 자동으로 값을 메모리에서 삭제 합니다.
도달 불가능 값이라... 쉽게 말해서 내가 생성한 객체를 참조하고 있는 변수의 값을 null 로 변경하면 더이상 우리는 그 객체에 접근할 수 없습니다. 이것을 도달 불가능하다 라고 합니다.
객체,배열,맵,셋 등의 자료구조 안에 속한 값은 그 값을 참조하는 변수를 null 로 바꾼다해도 해당 자료구조가 메모리에 존재하는 동안에는 도달 가능한 값으로 취급되어 메모리에서 삭제가 되지 않습니다. 예를 들어보겠습니다.
let footballPlayer = {
name : "kane",
}
const footballClub = [footballPlayer];
footballPlayer = null;
console.log(footballClub.length); // 1
위의 코드와 같이 footballPlayer 라는 참조 변수를 가지는 객체에 name 이라는 프로퍼티에 "kane" 을 저장하고 footballClub 배열의 요소에 footballPlayer 객체를 추가했습니다. 그리고 footballPlayer 참조 변수의 값을 null 로 변경했습니다. 이때 배열에 저장된 객체는 참조 값을 잃게 되어 더이상 도달하지 못하는 객체가 되었습니다. 그럼 우리가 배운대로 가비지 컬렉터가 메모리에서 삭제를 할 것 입니다.
하지만 이 객체는 메모리에서 삭제되지 않습니다. footballClub 배열이 메모리에 남아있다면 이 객체의 가비지 컬렉터의 대상에 포함되지 않아 메모리에 남아있게 됩니다.
실제로 length 를 사용하여 배열의 길이를 확인해봐도 1 인것을 확인할 수 있습니다. footballClub[0] 을 이용하면 객체를 얻는것도 가능합니다.
그럼 요번 시간의 주인공인 위크맵에 대해서 알아봅시다.
생성 방법은 new WeakMap() 으로 생성 합니다.
위크맵은 기존의 객체,배열,맵,셋과 같은 자료구조와 다른 특징을 가지고 있습니다.
1. 위크맵의 키 값은 항상 객체여야 합니다.
위크맵은 위에 일반적인 자료구조와 다르게 객체만 키 값으로 사용할 수 있습니다. 그리고 그 객체를 참조하는 참조변수의 값을 null 로 변경하면 이 객체를 참조하고 있는 참조변수가 없다면 도달 불가능하기때문에 위크맵에서는 key 값인 객체와 해당하는 value 값도 같이 메로리에서 삭제되고 위크맵에서도 삭제 됩니다.
왜 전체 key, value 값을 못가지고 오도록 메서드가 존재하지 않는걸까요?
그 이유는 key 값의 객체를 참조하는 참조변수를 다른 값으로 변경하면 그 key와 해당하는 value 는 가비지 컬렉터의 삭제 대상이 됩니다. 하지만 가비지 컬렉터가 당장 삭제할지 한번에 나중에 삭제할지 부분적으로 삭제할지 자바스크립트 엔진이 결정하기 때문이죠 개발자는 언제 삭제할지 알 길이 없습니다. 그래서 정확이 key, value 전체 값을 가지고 올 수 없는 것 입니다.
그래서 weakMap 은 아래의 메서드만 지원 합니다.
그럼 weakMap 자료구조를 언제 쓰나요?
바로 객체에 관련된 추가 데이터를 기록하고 저장할때 사용 할 수 있습니다.
예를 들어 어떤 팀에서 우리팀 축구 선수들의 한시즌 골 기록을 저장해서 기록한다고 생각해 봅시다. 한시즌이 끝나면 이 기록은 초기화되기 때문에 객체 안에 프로퍼티 값으로 저장하는 것보다 유용합니다. 한시즌만 쓰고 weakMap 자료구조의 모든 값을 날려 버리면 되는거죠 그리고 우리팀 선수가 다른 팀으로 이적했다면 이제 그 선수의 기록을 저장해서 기록해둘 필요가 없겠죠. 이때 그 선수를 참조하고 있던 참조변수를 null 로 바꿔 그 객체를 weakMap 안에서 쉽게 날려버릴 수 있습니다. 코드로 확인 해 봅시다.
let footballPlayerKane = {
name : "kane",
}
let footballPlayerSon = {
name : "son",
}
let footballPlayerCasemiro = {
name : "casemiro",
}
const footballClub = new weakMap()
footballClub.set(footballPlayerKane,0);
footballClub.set(footballPlayerSon,0);
footballClub.set(footballPlayerCasemiro,0);
function CountGoal(player) {
let goal = footballClub.get(player);
footballClub.set(player, goal+1);
}
countGoal(footballPlayerKane); // kane 1
countGoal(footballPlayerKane); // kane 2
countGoal(footballPlayerSon); // son 1
countGoal(footballPlayerKane); // kane 3
countGoal(footballPlayerCasemiro); // casemiro 1
// 카세미루 이적
footballPlyerCasemiro = null;
위의 코드와 같이 kane, son, casemiro 선수의 한시즌 골 기록을 WeakMap() 자료구조를 사용해서 기록할려고 합니다. 선수가 골을 넣을때마다 countGoal 함수에 인자로 골을 넣은 선수의 참조변수 key 를 전달해 value 값을 +1 하도록 코드를 작성하였습니다. 이렇게 시즌이 진행 되다가 casemiro 선수가 이적하였습니다. 이제부터 casemiro 선수의 골 기록을 기록해서 저장할 필요가 없습니다. 그래서 casemiro 선수의 객체를 참조하는 참조변수의 값을 null 로 변경해 객체에 도달하지 못하는 상태로 만들면 자동으로 WeakMap 자료구조에서 casemiro 선수에대한 key, value 는 삭제 됩니다. 이 예와 같이 데이터의 추가 데이터를 관리할때 WeakMap 자료구조를 사용하면 아주 편리 합니다.
캐싱은 시간이 오래걸리는 작업을 저장해서 그 작업을 다시 해야할때 저장한 것을 바로 사용해 시간과 비용을 절약하는 방법 입니다. 같은 함수를 자주 호출해야할때 반환 값을 저장해두고 그 함수가 호출되면 호출해 함수를 실행하지 않고 반환 값을 바로 반환해주는 것 입니다. 일반적인 map 을 사용한다면 이제 그 객체가 필요 없어져 자료구조에서 삭제 한다면 그 반환 값도 삭제해 줘야 합니다. 하지만 WeakMap 자료구조를 사용하면 캐싱으로 반환값을 저장해뒀다가 이제 그 객체를 사용할 필요가 없어지면 객체를 도달하지 못하게 만들면 그 객체와 캐싱 값은 자동적으로 WeakMap 자료구조와 메모리에서 삭제할 수 있습니다.
위크셋이라는 자료구조도 있습니다.
생성 방법은 new WeakSet() 으로 생성 합니다.
1. 위크셋은 셋과 유사하지만 값으로 객체만 저장할 수 있습니다.
2. 셋의 값은 객체가 도달 가능할때까지만 값이 유지됩니다.
3. 위크맵과 같이 반복에 필요한 메서드는 지원하지 않습니다. add, hsa, delet 메서드를 사용할 수 있습니다.
그럼 위크셋은 어디에 사용할 수 있나?
멤버관리,방문기록 등 이런것을 구현할때 사용하면 유용합니다. 필요없는 객체는 도달하지 못하게 만들어 객체를 WeakSet 자료구조와 메모리에서 삭제할 수 있기 때문입니다.