javaScript - 위크맵과 위크셋

뭐 그냥 하는거지·2023년 2월 10일
0
post-thumbnail

자바스크립트 엔진은 도달이 불가능한 값을 가비지 컬렉션을 통해 자동으로 값을 메모리에서 삭제 합니다.
도달 불가능 값이라... 쉽게 말해서 내가 생성한 객체를 참조하고 있는 변수의 값을 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] 을 이용하면 객체를 얻는것도 가능합니다.

WeakMap

그럼 요번 시간의 주인공인 위크맵에 대해서 알아봅시다.
생성 방법은 new WeakMap() 으로 생성 합니다.
위크맵은 기존의 객체,배열,맵,셋과 같은 자료구조와 다른 특징을 가지고 있습니다.
1. 위크맵의 키 값은 항상 객체여야 합니다.

위크맵은 위에 일반적인 자료구조와 다르게 객체만 키 값으로 사용할 수 있습니다. 그리고 그 객체를 참조하는 참조변수의 값을 null 로 변경하면 이 객체를 참조하고 있는 참조변수가 없다면 도달 불가능하기때문에 위크맵에서는 key 값인 객체와 해당하는 value 값도 같이 메로리에서 삭제되고 위크맵에서도 삭제 됩니다.

  1. 위크맵은 맵과 같이 반복작업을 할때 도움을 주는 메서드(keys(), values(), entries() ) 를 사용할 수 없습니다. 한번에 위크맵의 전체 데이터를 가져올 수 없습니다.

왜 전체 key, value 값을 못가지고 오도록 메서드가 존재하지 않는걸까요?
그 이유는 key 값의 객체를 참조하는 참조변수를 다른 값으로 변경하면 그 key와 해당하는 value 는 가비지 컬렉터의 삭제 대상이 됩니다. 하지만 가비지 컬렉터가 당장 삭제할지 한번에 나중에 삭제할지 부분적으로 삭제할지 자바스크립트 엔진이 결정하기 때문이죠 개발자는 언제 삭제할지 알 길이 없습니다. 그래서 정확이 key, value 전체 값을 가지고 올 수 없는 것 입니다.
그래서 weakMap 은 아래의 메서드만 지원 합니다.

  • weakMap.set(key(객체),value)
  • weakMap.get(key(객체))
  • weakMap.delete(key(객체))
  • weakMap.clear()
    위의 메서드는 Map 과 같은 기능을 가집니다.

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 자료구조를 사용하면 아주 편리 합니다.

WeakMap - 캐싱

캐싱은 시간이 오래걸리는 작업을 저장해서 그 작업을 다시 해야할때 저장한 것을 바로 사용해 시간과 비용을 절약하는 방법 입니다. 같은 함수를 자주 호출해야할때 반환 값을 저장해두고 그 함수가 호출되면 호출해 함수를 실행하지 않고 반환 값을 바로 반환해주는 것 입니다. 일반적인 map 을 사용한다면 이제 그 객체가 필요 없어져 자료구조에서 삭제 한다면 그 반환 값도 삭제해 줘야 합니다. 하지만 WeakMap 자료구조를 사용하면 캐싱으로 반환값을 저장해뒀다가 이제 그 객체를 사용할 필요가 없어지면 객체를 도달하지 못하게 만들면 그 객체와 캐싱 값은 자동적으로 WeakMap 자료구조와 메모리에서 삭제할 수 있습니다.

WeakSet

위크셋이라는 자료구조도 있습니다.
생성 방법은 new WeakSet() 으로 생성 합니다.
1. 위크셋은 셋과 유사하지만 값으로 객체만 저장할 수 있습니다.
2. 셋의 값은 객체가 도달 가능할때까지만 값이 유지됩니다.
3. 위크맵과 같이 반복에 필요한 메서드는 지원하지 않습니다. add, hsa, delet 메서드를 사용할 수 있습니다.
그럼 위크셋은 어디에 사용할 수 있나?
멤버관리,방문기록 등 이런것을 구현할때 사용하면 유용합니다. 필요없는 객체는 도달하지 못하게 만들어 객체를 WeakSet 자료구조와 메모리에서 삭제할 수 있기 때문입니다.

0개의 댓글