es 6 javascriptのWeakMap構造

2435 ワード

WeakMapとMapの構造は基本的に似ていますが、唯一の違いは相手をキーとして受け入れることです.他の種類の値をキーとして受け入れません.そしてキーの名前が指す対象はゴミ回収メカニズムに含まれません.
var map = new WeakMap();
map.set(1, 2);
// TypeError: 1 is not an object!
map.set(Symbol(), 2);
// TypeError: Invalid value used as weak map key
上のコードの中で、1とSymbolをWeakMapのキーとすると、エラーが発生します.
WeakMapの設計目的は、キーの名前が対象の弱い引用(ゴミ回収メカニズムは引用を考慮に入れない)であるため、対応する対象は自動的に回収される可能性がある.対象が回収されたら、WeakMapは対応するキーのペアを自動的に削除します.典型的なアプリケーションは、DOM要素に対応するWeakMap構造が、あるDOM要素がクリアされると、対応するWeakMapレコードが自動的に取り除かれる.基本的に、WeakMapの専用の場合は、そのキーに対応するオブジェクトは、将来的には消える可能性があります.WeakMap構造はメモリ漏れ防止に役立つ.
以下はWeakMap構造の一例です.使い方はMapとほぼ同じです.
var wm = new WeakMap();
var element = document.querySelector(".element");
wm.set(element, "Original");
wm.get(element) // "Original"
element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined
上のコードの中で、変数wmはWeakMapの例です.私達はDOMノードelementをキー名として廃棄して、このノードを破壊します.element対応のキーは自動的に消えてしまいました.このキーを引用してundefinedに戻ります.
WeakMapとMapのAPIにおける違いは主に二つであり、一つは操作を巡回していない(すなわちkey()、values()とentries()方法がなく、またsize属性がないことである.二つ目はクリアできません.つまり、clear方法はサポートされていません.これはWeakMapのキーが参照に含まれず、ゴミ回収機構に無視されていることと関係があります.したがって、WeakMapは、get()、set()、has()、delete()の4つの方法しか利用できません.
var wm = new WeakMap();
wm.size
// undefined
wm.forEach
// undefined
    , WeakMap           DOM       。        。
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();
myWeakmap.set(myElement, {
	timesClicked: 0
});
myElement.addEventListener('click', function() {
	let logoData = myWeakmap.get(myElement);
	logoData.timesClicked++;
	myWeakmap.set(myElement, logoData);
}, false);
上のコードの中で、myElementはDOMノードです.clickイベントが発生するたびに、状態を更新します.私たちはこの状態をキーとしてWeakMapに置きます.対応するキーの名前はmyElementです.このDOMノードが削除されると、この状態は自動的に消え、メモリ漏れのリスクがない.
WeakMapのもう一つの用途はプライベート属性の配置である.
let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
	constructor(counter, action) {
		_counter.set(this, counter);
		_action.set(this, action);
	}
	dec() {
		let counter = _counter.get(this);
		if(counter < 1) return;
		counter--;
		_counter.set(this, counter);
		if(counter === 0) {
			_action.get(this)();
		}
	}
}
let c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
// DONE
上のコードのうち、Countdown類の2つの内部属性_counterと_actionは、インスタンスの弱い参照ですので、インスタンスを削除すると、それらはすぐに消えてしまい、メモリ漏れの原因になりません.