これとこのMDNページを見ると、MapsとWeakMapsの唯一の違いは、WeakMapsの「size」プロパティが欠落していることのようです。しかし、これは本当ですか?それらの違いは何ですか?
7 に答える
キー/値によって参照されるオブジェクトが削除されると、両方の動作が異なります。以下のサンプルコードを見てみましょう。
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を使用すると、ガベージコレクターはそのタスクを実行できますが、Mapは実行できません。
参照: 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
も、マップ内でキーにアクセスできます。同時に、k2
WeakMapのキーを削除するとwm
、参照によってそれも削除されます。
そのため、WeakMapにはforEachのような列挙可能なメソッドがありません。これは、WeakMapキーのリストなどがなく、別のオブジェクトへの参照にすぎないためです。
まったく同じページの「なぜマップが弱いのか」のセクション:
経験豊富なJavaScriptプログラマーは、このAPIが4つのAPIメソッドで共有される2つの配列(1つはキー用、もう1つは値用)を使用してJavaScriptで実装できることに気付くでしょう。このような実装には、2つの主な不便があります。1つ目はO(n)検索です(nはマップ内のキーの数です)。2つ目は、メモリリークの問題です。手動で作成されたマップを使用すると、キーの配列はキーオブジェクトへの参照を保持し、それらがガベージコレクションされるのを防ぎます。ネイティブのWeakMapsでは、キーオブジェクトへの参照は「弱く」保持されます。つまり、オブジェクトへの他の参照がない場合でも、ガベージコレクションが妨げられることはありません。
参照が弱いため、WeakMapキーは列挙できません(つまり、キーのリストを提供するメソッドはありません)。もしそうなら、リストはガベージコレクションの状態に依存し、非決定論を導入します。
size
[そしてそれが彼らにも財産がない理由です]
キーのリストが必要な場合は、自分で管理する必要があります。 弱参照を使用せず、列挙可能な単純なセットとマップを導入することを目的としたECMAScriptの提案もあります。
‐これは「通常の」Map
sになります。MDNでは言及されていませんが、ハーモニーの提案では、それらにもitems
、ジェネレーターメソッドがあり、インターフェイスを実装してkeys
います。values
Iterator
別の違い(出典:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
WeakMapsのキーは、オブジェクトタイプのみです。キーとしてのプリミティブデータ型は許可されていません(たとえば、SymbolをWeakMapキーにすることはできません)。
文字列、数字、ブール値をWeakMap
キーとして使用することもできません。キーにプリミティブ値を使用Map
できます。
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.infoから
マップ-通常のマップでキーとしてオブジェクトを使用する場合、マップが存在する間、そのオブジェクトも存在します。メモリを占有し、ガベージコレクションされない場合があります。
let john = { name: "John" };
let array = [ john ];
john = null; // overwrite the reference
// john is stored inside the array, so it won't be garbage-collected
// we can get it as array[0]
同様に、通常のマップでキーとしてオブジェクトを使用する場合、マップが存在する間、そのオブジェクトも存在します。メモリを占有し、ガベージコレクションされない場合があります
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // overwrite the reference
// john is stored inside the map,
// we can get it by using map.keys()
WeakMap-オブジェクトをキーとして使用し、そのオブジェクトへの他の参照がない場合、オブジェクトはメモリ(およびマップ)から自動的に削除されます。
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!
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には次のメソッドしかありません。
- weakMap.get(key)
- weakMap.set(key、value)
- weakMap.delete(key)
- weakMap.has(key)
これは、オブジェクトが他のすべての参照(上記のコードの「user」など)を失った場合と同様に、自動的にガベージコレクションされることは明らかです。ただし、技術的には、クリーンアップがいつ行われるかは正確には指定されていません。
JavaScriptエンジンがそれを決定します。すぐにメモリのクリーンアップを実行するか、後でさらに削除が発生したときに待機してクリーニングを実行するかを選択できます。したがって、技術的には、aの現在の要素数WeakMap
は不明です。エンジンがクリーンアップしたかどうか、または部分的に実行した可能性があります。そのため、すべてのキー/値にアクセスするメソッドはサポートされていません。
注: -WeakMapの主なアプリケーション領域は、追加のデータストレージです。オブジェクトがガベージコレクションされるまでオブジェクトをキャッシュするようなものです。
javascriptのWeapMapはキーや値を保持せず、一意のIDを使用してキー値を操作し、キーオブジェクトにプロパティを定義するだけです。
key object
メソッドによってプロパティを定義するためObject.definePropert()
、キーはプリミティブ型であってはなりません。
また、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;
})();
実装のリファレンス