this および this MDNページを見ると、MapsとWeakMapsの唯一の違いは、WeakMapsの「サイズ」プロパティが欠落しているようです。しかし、これは本当ですか?それらの違いは何ですか?
まったく同じページのセクション「WhyWeakMap?」 :
経験豊富なJavaScriptプログラマは、このAPIが4つのAPIメソッドで共有される2つの配列(キー用、値用)を持つJavaScriptで実装できることに気付くでしょう。このような実装には、主に2つの不都合があります。 1つ目はO(n)検索(nはマップ内のキーの数です)。2つ目はメモリリークの問題です。手動で作成したマップでは、キーの配列はキーオブジェクトへの参照を保持し、ガベージコレクションされないようにします。ネイティブWeakMapsでは、キーオブジェクトへの参照が保持されます "weakly"、つまり、オブジェクトへの他の参照がない場合にガベージコレクションを妨げないことを意味します。
参照が弱いため、WeakMapキーは列挙できません(つまり、キーのリストを提供するメソッドはありません)。存在する場合、リストはガベージコレクションの状態に依存し、非決定性をもたらします。
[だからこそ、size
プロパティもありません]
キーのリストが必要な場合は、自分で管理する必要があります。 ECMAScript提案 もあります。これは、弱参照を使用せず、列挙可能な単純なセットとマップを導入することを目的としています。
‐これは "normal" Map
s になります。 MDNでは言及されていませんが、 調和提案 では、items
、keys
、およびvalues
ジェネレーターメソッドもあり、 Iterator
インターフェイス 。
キー/値によって参照されるオブジェクトが削除されると、両者は異なる動作をします。以下のサンプルコードを見てみましょう。
var map = new Map();
var weakmap = new WeakMap();
(function(){
var a = {x: 12};
var b = {y: 12};
map.set(a, 1);
weakmap.set(b, 2);
})()
上記のIIFEが実行されると、{x: 12}
および{y: 12}
を参照できなくなります。ガベージコレクターは先に進み、「WeakMap」からキーbポインターを削除し、メモリから{y: 12}
も削除します。ただし、「マップ」の場合、ガベージコレクターは「マップ」からポインターを削除せず、{x: 12}
もメモリから削除しません。
概要:WeakMapを使用すると、ガベージコレクターはタスクを実行できますが、マップは実行できません。
参照: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
次の説明は誰かにとってもっと明確になるでしょう。
var k1 = {a: 1};
var k2 = {b: 2};
var map = new Map();
var wm = new WeakMap();
map.set(k1, 'k1');
wm.set(k2, 'k2');
k1 = null;
map.forEach(function (val, key) {
console.log(key, val); // k1 {a: 1}
});
k2 = null;
wm.get(k2); // undefined
ご覧のとおり、メモリからk1
キーを削除した後でも、マップ内でアクセスできます。同時に、WeakMapのk2
キーを削除すると、参照によってwm
からも削除されます。
そのため、WeakMapにはforEachのような列挙可能なメソッドがありません。これは、WeakMapキーのリストなどはなく、別のオブジェクトへの参照にすぎないためです。
別の違い(ソース: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
WeakMapsのキーは、Object型のみです。キーとしてのプリミティブデータ型は許可されません(たとえば、SymbolをWeakMapキーにすることはできません)。
文字列、数値、またはブール値をWeakMap
キーとして使用することもできません。 Map
canは、キーにプリミティブ値を使用します。
w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key
m = new Map
m.set('a', 'b'); // Works
JavascriptのWeapMapはキーや値を保持せず、一意のidを使用してキー値を操作し、キーオブジェクトにプロパティを定義します。
メソッドObject.definePropert()
によってkey
にプロパティを定義するため、キーはプリミティブ型であってはなりません。
また、WeapMapには実際にはキーと値のペアが含まれていないため、weakmapのlengthプロパティを取得できません。
また、操作された値がキーに割り当てられるため、ガベージコレクターは、使用されていない場合でも簡単にキーを収集できます。
実装用のサンプルコード。
if(typeof WeapMap != undefined){
return;
}
(function(){
var WeapMap = function(){
this.__id = '__weakmap__';
}
weakmap.set = function(key,value){
var pVal = key[this.__id];
if(pVal && pVal[0] == key){
pVal[1]=value;
}else{
Object.defineProperty(key, this.__id, {value:[key,value]});
return this;
}
}
window.WeakMap = WeakMap;
})();
実装 の参照
WeakMap
キーは、プリミティブ値ではなくオブジェクトでなければなりません。
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "ok"); // works fine (object key)
// can't use a string as the key
weakMap.set("test", "Not ok"); // Error, because "test" is not an object
なぜ????
以下の例を見てみましょう。
let user = { name: "User" };
let map = new Map();
map.set(user, "...");
user = null; // overwrite the reference
// 'user' is stored inside the map,
// We can get it by using map.keys()
通常の
Map
のキーとしてオブジェクトを使用する場合、Map
が存在する間、そのオブジェクトも存在します。メモリを占有し、ガベージコレクションされない場合があります。
WeakMap
はこの点で根本的に異なります。キーオブジェクトのガベージコレクションは妨げられません。
let user = { name: "User" };
let weakMap = new WeakMap();
weakMap.set(user, "...");
user = null; // overwrite the reference
// 'user' is removed from memory!
オブジェクトをキーとして使用し、そのオブジェクトへの他の参照がない場合、メモリから(およびマップから)自動的に削除されます。
WeakMap
しない反復とメソッドをサポートするkeys()、 values()、entries()、したがって、そこからすべてのキーまたは値を取得する方法はありません。
WeakMapには次のメソッドのみがあります。
オブジェクトが他のすべての参照(上記のコードの「ユーザー」など)を失った場合、オブジェクトは自動的にガベージコレクションされることになります。ただし、技術的には、クリーンアップがいつ行われるかは正確には指定されていません。
JavaScriptエンジンがそれを決定します。メモリクリーンアップをすぐに実行するか、削除がさらに発生したときに待機して後でクリーニングを実行するかを選択できます。そのため、技術的にはWeakMap
の現在の要素数は不明です。エンジンがクリーンアップしたかどうか、または部分的に実行した可能性があります。そのため、すべてのキー/値にアクセスするメソッドはサポートされていません。
注:- WeakMapのアプリケーションの主な領域は、追加のデータストレージです。オブジェクトがガベージコレクトされるまでオブジェクトをキャッシュするようなものです。