ES6 MapとWeakMapの違いは何ですか?


93

これこの MDNページを見ると、MapsとWeakMapsの唯一の違いはWeakMapsの "サイズ"プロパティがないことです。しかし、これは本当ですか?それらの違いは何ですか?


影響はGCにあります。WeakMapsはキーを収集できます。
John Dvorak

@JanDvorak MDNで指摘された例はありません。同様にaWeakMap.get(key); //言う、2 ...(GCアクション)... aWeakMap.get(key); //未定義と言う
Dmitrii Sorin 2013

1
あなたの例は不可能です。keyあなたが参照しているため、収集できません。
John Dvorak

1
設計上の決定は、GCアクションはJavascriptでは見えないことです。GCの動作を監視することはできません。
John Dvorak

1
この問題の詳細については、この関連回答を参照してください。
Benjamin Gruenbaum 2015

回答:


53

非常に同じページ、セクション「なぜ弱い地図?

経験豊富なJavaScriptプログラマーは、このAPIが4つのAPIメソッドで共有される2つの配列(1つはキー、もう1つは値)を使用してJavaScriptに実装できることに気付くでしょう。このような実装には2つの主要な不便があります。最初の検索はO(n)検索です(nはマップ内のキーの数です)。2つ目はメモリリークの問題です。手動で作成されたマップでは、キーの配列はキーオブジェクトへの参照を保持し、それらがガベージコレクションされるのを防ぎます。ネイティブのWeakMapでは、キーオブジェクトへの参照は「弱く」保持されます。つまり、オブジェクトへの参照が他にない場合でも、ガベージコレクションが妨げられることはありません。

参照が弱いため、WeakMapキーは列挙できません(つまり、キーのリストを提供するメソッドはありません)。もしそうなら、リストはガベージコレクションの状態に依存し、非決定論を導入します。

[そして、それが彼らにもsize財産がない理由です]

キーのリストが必要な場合は、自分で管理する必要があります。 弱い参照を使用せず、列挙可能な単純なセットとマップの導入を目的としたECMAScript提案もあります。

‐これが「通常の」Mapsになります。MDNで述べた、しかしでない調和の提案、それらも持っているitemskeysvalues発電方法を、実施Iteratorのインターフェイスを


そうnew Map().get(x)平野オブジェクトからプロパティを読み込むと同じルックアップ時間について持っていますか?
Alexander Mills

1
@AlexanderMillsこれが質問とどう関係しているのかわかりませんが、ここにいくつかのデータがあります。一般に、はい、それらは似ています適切なものを使用する必要があります
ベルギ

したがって、私の理解では、Mapは内部配列を維持して、その配列のためにそのキーを永続化します。ガベージコレクターは参照を控えることができません。WeekMapでは、キーが維持される配列がないため、参照のないキーをガベージコレクションできます。
Mohan Ram、

@MohanRam AにはWeakMapまだエントリの配列(または他のコレクション)があり、ガベージコレクターにそれらが弱い参照であることを伝えるだけです。
ベルギ

では、WeekMapキーの反復がサポートされていないのはなぜですか。
Mohan Ram、

92

キー/値で参照されているオブジェクトが削除されると、どちらも動作が異なります。以下のサンプルコードを見てみましょう:

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);
})()

上記の生命維持には、私たちが参照できる方法はありませんが実行される{x: 12}と、{y: 12}もはやは。ガベージコレクターは先に進み、「WeakMap」からキーbポインターを削除し{y: 12}、メモリからも削除します。ただし、「マップ」の場合、ガベージコレクターは「マップ」からポインターを削除せず{x: 12}、メモリからも削除しません。

概要:WeakMapを使用すると、ガベージコレクターはタスクを実行できますが、マップは実行できません。

参照:http : //qnimate.com/difference-between-map-and-weakmap-in-javascript/


12
なぜメモリから削除されないのですか?それでも参照できるからです!map.entries().next().value // [{x:12}, 1]
Bergi、

4
これは自己起動関数ではありません。これは、即座に呼び出される関数式です。benalman.com/news/2010/11/...
Olson.dev

次に、weakmapとオブジェクトの違いは何ですか
Muhammad

@MuhammadUmer:オブジェクトは文字列「キー」のみを持つことができますが、WeakMap非プリミティブキーのみを持つことができます(Symbolキーとしての文字列または数値またはsはなく、配列、オブジェクト、その他のマップなどのみ)。
Ahmed Fasih

1
@nnnnnnはい、それは違いです。それはまだにありますMap が、そうではありませんWeakMap
Alexander Derck

75

多分次の説明は誰かのためにより明確になるでしょう。

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、メモリからキーを削除した後も、マップ内でキーにアクセスできます。同時に、k2WeakMapのキーを削除すると、wm参照からも削除されます。

そのため、WeakMapにはforEachのような列挙可能なメソッドがありません。これは、WeakMapキーのリストなどがないため、別のオブジェクトへの参照にすぎません。


10
もちろん、最終行では、wm.get(null)は未定義になります。
DaNeSh

8
Mozillaサイトのkudosからコピーして貼り付けるよりも良い答えです。
Joel Hernandez

2
forEach(key, val)実際にもしなければならない(val, key)
ミゲル・モタ

意味のない例が非常に多くの賛成票を獲得する方法は信じられないほどです
alfredopacino

34

別の違い(ソース:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap):

WeakMapsのキーは、オブジェクトタイプのみです。キーとしてのプリミティブデータタイプは許可されません(たとえば、シンボルを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

6
誰かが不思議に思った場合:この背後にある理由は想像できます:プリミティブ型への参照を保持または渡すことはできません。したがって、WeakMapのキーは、これまでの唯一の参照になります。そうすれば、ガベージコレクションは不可能になります。弱い参照が不可能なのか、それとも意味がないのかわかりません。しかし、どちらの方法でも、キーは弱く参照できるものである必要があります。
Andreas Linnert 2016年

3

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]

同様に、通常のMapでキーとしてオブジェクトを使用すると、Mapが存在する間、そのオブジェクトも存在します。メモリを占有し、ガベージコレクションされない可能性があります

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!

3

JavaScriptのWeapMapはキーや値を保持せず、一意のIDを使用してキー値を操作し、キーオブジェクトにプロパティを定義します。

key objectメソッドによってプロパティを定義するためObject.definePropert()キーはプリミティブ型であってはなりません

また、WeapMapには実際にはキーと値のペアが含まれていないため、weakmapの長さプロパティを取得できません。

また、操作された値がキーオブジェクトに割り当てられるため、ガベージコレクターは、キーが使用されなくなった場合でも簡単にキーを収集できます。

実装のためのサンプルコード。

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;
})();

実装のリファレンス


1
明確にするために、この実装は半分しか機能しません。複数の弱いマップで同じオブジェクトをキーとして使用することはできません。また、フリーズしたオブジェクトには機能しません。そしてもちろん、オブジェクトへの参照を持つすべての人にマッピングをリークします。前者はシンボルを使用して修正できますが、後者は修正できません。
Andreas Rossberg

@AndreasRossbergこの実装ではハードコードを追加しましたidが、Math.randomやDate.now()などを使用して一意にする必要があります。この動的IDを追加することで、最初の点を解決できます。最後の2つのポイントの解決策を提供していただけませんか。
Ravi Sevta

最初の問題は、シンボルを使用することでよりエレガントに解決されます。後者の2つはJS内で解決できません。そのため、WeakMapは言語のプリミティブである必要があります。
Andreas Rossberg

1

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のアプリケーションの主な領域は、追加のデータストレージです。オブジェクトがガベージコレクションされるまでオブジェクトをキャッシュするように。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.