weakMap을 이용한 singleton 패턴
February 20, 2021
이글을 작성하는 이유?
- 코드스피치 유튜브 영상에서 소개한 Singleton Pattern에 대해서 공유하고 싶어서
- Map 과 WeakMap에 대해서 정확한 차이를 알고 싶어서
Singleton Pattern : 단 하나의 인스턴스만 생성되고 사용되어 진다.
-
어디에서 불러내고 요청되도 인스턴스는 언제나 하나(Singleton 유지)
App 개발에서 메모리 Context에 따라 세가지의 Singleton
- Application Memory : 서버가 죽을때까지의 메모리
- Session Memory : 유저가 로그인하고 로그아웃 할때까지의 메모리
- Request Memory : 하나의 요청당 하나의 메모리
JavaScript에서 SingleTon을 구현하는 방법
1. closure + IIFE (from ZeroCho)
-
ES6 이전에 구현하는 방법
var singleton = (function() { var instance; var a = 'hello'; function initiate() { return { a: a, b: function() { alert(a); } }; } return { getInstance: function() { if (!instance) { instance = initiate(); } return instance; } } })(); var first = singleton.getInstance(); var second = singleton.getInstance(); console.log(first === second); // true;
2. WeakMap (from CodeSpitz)
- Map과 다른점은 Key에 참조값만 넣을 수 있다! ⇒ Key가 객체이다
- 어떤 객체를 기반으로 무언가 값을 얻어내고 싶으면, WeakMap 사용
-
weakMap의 내장 메소드를 에러처리하여, Singleton의 역할만 할 수 있게!
const Singleton = class extends WeakMap{ has(){err()}; get(){err()}; set(){err()}; getInstance(v){ if(!super.has(v.constructor)) super.set(v.constructor, v); return super.get(v.constructor); } } const singleton = new Singleton; const Test = class { constructor (isSingleton) { if(isSingleton) return singleton.getInstance(this); } } const test1 = new Test(true), test2 = new Test(true), test3 = new Test(); console.log(test1 === test2); //true console.log(test2 === test3); //false
Map이 있는데… WeakMap은 왜 쓸까?
1. 등장배경
-
JS 엔진은 Mark And Sweap 알고리즘 방식으로 메모리를 관리한다
let john = { name: "John" }; john = null; // 더이상 쓰이지 않아, 메모리에서 삭제! john = { name: "John" }; let array = [ john ]; // array[0]는 john 객체을 참조 john = null; // 참조를 null로 덮어씀 // john을 나타내는 객체는 배열의 요소이기 때문에 가비지 컬렉터의 대상이 되지 않습니다. // array[0]을 이용하면 해당 객체를 얻는 것도 가능합니다. console.log(JSON.stringify(array[0])); //{ "name": "John" }
-
Map에서 객체를 키로 사용한 경우, Map이 메모리에 있는 한 객체도 메모리에 남아 있는다(가비지 컬렉터의 대상이 되지 않는다)
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);
2. WeakMap을 이용하여 객체를 키로 사용할때 발생하는 문제를 해결할 수 있다
- john을 나타내는 객체는 오로지 위크맵의 키로만 사용되고 있으므로,
-
참조를 덮어쓰게 되면 객체는 위크맵과 메모리에서 자동으로 삭제됩니다.
let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // 참조를 덮어씀 // john을 나타내는 객체는 이제 메모리에서 지워집니다!