ES6 Map ile WeakMap arasındaki fark nedir?


94

Looking bu ve bu onu Maps ve WeakMaps arasındaki tek fark gibi görünüyor MDN sayfaları WeakMaps için kayıp "boyutu" özelliktir. Ama bu doğru mu? Aralarındaki fark nedir?


Etkisi GC üzerindedir. WeakMap'ler anahtarlarını alabilir.
John Dvorak

@JanDvorak MDN'de bununla ilgili bir örnek yok. AWeakMap.get (key) gibi; // sayın, 2 ... (GC eylemi) ... aWeakMap.get (key); // söyle, tanımsız
Dmitrii Sorin

1
Örneğiniz imkansız. keysizin tarafınızdan referans verildiği için toplanamaz.
John Dvorak

1
Tasarım kararı, GC eylemlerinin Javascript'te görünmez olmasıdır. GC'nin işini yaptığını gözlemleyemezsiniz.
John Dvorak

1
Bu sorunla ilgili daha fazla bilgi için bu ilgili yanıta bakın .
Benjamin Gruenbaum

Yanıtlar:


54

Gönderen çok aynı sayfada, bölüm " Neden Zayıf Harita? " :

Deneyimli JavaScript programcısı, bu API'nin JavaScript'te 4 API yöntemi tarafından paylaşılan iki diziyle (biri anahtarlar için, biri değerler için) uygulanabileceğini fark edecektir. Böyle bir uygulamanın iki ana sakıncası olacaktır. İlki bir O (n) aramasıdır (n, haritadaki tuşların sayısıdır). İkincisi, bellek sızıntısı sorunudur. Manuel olarak yazılan haritalarda, anahtar dizisi, anahtar nesnelere referansları saklar ve bunların gereksiz yere toplanmasını engeller. Yerel WeakMaps'te, anahtar nesnelere yapılan başvurular "zayıf" tutulur ; bu, nesneye başka bir başvuru olmaması durumunda çöp toplamayı engellemedikleri anlamına gelir.

Referansların zayıf olması nedeniyle, WeakMap anahtarları numaralandırılamaz (yani, size anahtarların bir listesini veren bir yöntem yoktur). Öyle olsalardı, liste çöp toplama durumuna bağlı olacak ve determinizm olmayacaktı.

[Ve bu yüzden sizemülkleri de yok ]

Bir anahtar listesine sahip olmak istiyorsanız, bunu kendiniz korumalısınız. Zayıf referanslar kullanmayan ve numaralandırılabilir basit setler ve haritalar sunmayı amaçlayan bir ECMAScript önerisi de vardır .

- "normal" Mapler olurdu . MDN'yi de belirtildiği, ancak içinde değil uyum önerisi , o da var items, keysve valuesjeneratör yöntem ve uygulamak Iteratorarabirimi .


bu nedenle new Map().get(x), bir özelliği düz bir nesneden okumakla yaklaşık aynı arama süresine sahiptir?
Alexander Mills

1
@AlexanderMills Bunun soruyla ne ilgisi olduğunu anlamıyorum, ama işte bazı veriler . Genel olarak, evet benzerler ve uygun olanı kullanmalısınız .
Bergi

Anladığım kadarıyla, Map, bu dizi nedeniyle anahtarını sürdürmek için dahili bir dizi tutar. Çöp toplayıcı referansı engelleyemez. WeekMap'te, anahtarların tutulduğu bir diziye sahip değildir, bu nedenle referansı olmayan anahtarlar çöp toplanabilir.
Mohan Ram

@MohanRam A WeakMaphala bir dizi (veya başka bir dizi) girdiye sahiptir, sadece çöp toplayıcıya bunların zayıf referanslar olduğunu söyler .
Bergi

O halde Hafta Haritası anahtarları için yineleme neden desteklenmiyor?
Mohan Ram

93

Anahtarları / değerleri tarafından referans verilen bir nesne silindiğinde her ikisi de farklı davranır. Aşağıdaki örnek kodu alalım:

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

Yukarıdaki IIFE, referans verebilmemizin hiçbir yolu yoktur {x: 12}ve {y: 12}artık yürütülmektedir . Çöp toplayıcı devam eder ve anahtar b işaretçisini "WeakMap" den siler ve ayrıca {y: 12}bellekten kaldırır . Ancak "Harita" durumunda, çöp toplayıcı "Harita" dan bir işaretçiyi kaldırmaz ve ayrıca {x: 12}bellekten de kaldırmaz .

Özet: WeakMap çöp toplayıcının görevini yapmasına izin verir, ancak Harita yapmasına izin vermez.

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


13
Neden hafızadan kaldırılmıyor? Çünkü ona hala başvurabilirsiniz! map.entries().next().value // [{x:12}, 1]
Bergi

4
Kendi kendine çağrılan bir işlev değildir. Hemen çağrılan bir işlev ifadesidir. benalman.com/news/2010/11/…
Olson.dev

o zaman zayıf harita ile nesne arasındaki fark nedir
Muhammad Umer

@MuhammadUmer: nesne yalnızca 'anahtarlara' WeakMapsahip olabilir , ancak yalnızca ilkel olmayan anahtarlara sahip olabilir (anahtar olarak dizeler, sayılar veya s'ler Symbol, yalnızca diziler, nesneler, diğer haritalar vb.).
Ahmed Fasih

1
@nnnnnn Evet fark bu, hala içinde Map ama değilWeakMap
Alexander Derck

76

Belki bir sonraki açıklama birisi için daha net olacaktır.

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

Gördüğünüz gibi k1, hafızadan anahtarı çıkardıktan sonra, ona haritanın içinden hala erişebiliyoruz. Aynı zamanda k2WeakMap anahtarının kaldırılması onu wmreferans olarak da kaldırır .

Bu nedenle WeakMap, forEach gibi numaralandırılabilir yöntemlere sahip değildir, çünkü WeakMap anahtarlarının listesi diye bir şey yoktur, bunlar yalnızca başka nesnelere referanslardır.


10
elbette son satırda wm.get (null) tanımsız olacaktır.
DaNeSh

8
Mozilla sitesinden kopyalayıp yapıştırmaktan daha iyi cevap, tebrikler.
Joel Hernandez

2
içinde forEach, (key, val)aslında olması gereken(val, key)
Miguel Mota

Mantıklı olmayan bir örneğin bu kadar çok oy alması inanılmaz
alfredopacino

34

Başka bir fark (kaynak: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):

WeakMaps anahtarları yalnızca Object tipindedir. Anahtar olarak ilkel veri türlerine izin verilmez (örneğin, bir Sembol bir WeakMap anahtarı olamaz).

Bir dizge, sayı veya mantıksal WeakMapanahtar olarak da kullanılamaz . A Map , anahtarlar için ilkel değerler kullanabilir.

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
Birinin merak etmesi durumunda: Bunun arkasındaki sebebi tahmin edebiliyorum: ilkel tiplere atıfta bulunamaz veya bunlara atıfta bulunamazsınız. Yani bir WeakMap'teki anahtar, şimdiye kadarki tek referansı olacaktır. Bu şekilde çöp toplama mümkün olmazdı. Zayıf referansların imkansız olup olmadığını veya mantıklı olmadığını bilmiyorum. Ancak her iki durumda da anahtarın zayıf bir şekilde referans verilebilecek bir şey olması gerekir.
Andreas Linnert

3

Gönderen Javascript.info

Harita - Normal bir Haritada anahtar olarak bir nesne kullanırsak, Harita varken o nesne de var olur. Hafızayı kaplar ve çöp toplanmayabilir.

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]

Buna benzer şekilde, normal bir Harita'da anahtar olarak bir nesne kullanırsak, Harita varken o nesne de var olur. Hafızayı kaplar ve çöp toplanmayabilir

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 - Şimdi, anahtar olarak bir nesneyi kullanırsak ve bu nesneye başka referanslar yoksa - otomatik olarak bellekten (ve haritadan) kaldırılacaktır.

let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference

// john is removed from memory!

3

Javascript'teki WeapMap herhangi bir anahtar veya değer içermez, sadece benzersiz bir kimlik kullanarak anahtar değerini işler ve anahtar nesneye bir özellik tanımlar.

özelliği key objectyönteme göre tanımladığından Object.definePropert(), anahtar ilkel tür olmamalıdır .

ve ayrıca WeapMap aslında anahtar değer çiftleri içermediğinden, zayıf haritanın uzunluk özelliğini alamıyoruz.

ve ayrıca manipüle edilen değer anahtar nesneye geri atanır, çöp toplayıcı kullanılmadığı takdirde anahtarı kolayca toplayabilir.

Uygulama için örnek kod.

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

uygulama referansı


1
Açık olmak gerekirse, bu uygulamanın sadece yarısı işe yarıyor. Birden çok zayıf haritada anahtar olarak aynı nesnenin kullanılmasına izin vermez. Ayrıca donmuş nesneler için de çalışmaz. Ve elbette, haritayı nesneye referansı olan herkese sızdırıyor. Birincisi semboller kullanılarak düzeltilebilir, ancak son ikisi olamaz.
Andreas Rossberg

@AndreasRossberg Bu uygulamada sabit kod ekledim id, ancak bu Math.random ve Date.now () vb. Kullanarak benzersiz olmalıdır. Ve bu dinamik kimliği ekleyerek ilk nokta çözülebilir. Lütfen son iki nokta için bana bir çözüm sunar mısınız?
Ravi sevta

İlk sorun, semboller kullanılarak daha zarif bir şekilde çözülür. Son ikisi JS içinde çözülemez, bu yüzden WeakMap'in dilde ilkel olması gerekir.
Andreas Rossberg

1

WeakMap anahtarlar, ilkel değerler değil, nesneler olmalıdır.

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

Neden????

Aşağıdaki örneğe bakalım.

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

Normalde anahtar olarak bir nesneyi kullanırsak Map, o zaman Mapvar olduğu sürece , o nesne de var olur. Hafızayı kaplar ve çöp toplanmayabilir.

WeakMapbu açıdan temelde farklıdır. Anahtar nesnelerin çöp toplanmasını engellemez.

let user = { name: "User" };

let weakMap = new WeakMap();
weakMap.set(user, "...");

user = null; // overwrite the reference

// 'user' is removed from memory!

Anahtar olarak bir nesneyi kullanırsak ve bu nesneye başka referanslar yoksa, bellekten (ve haritadan) otomatik olarak kaldırılacaktır.

WeakMap değil yineleme ve yöntemler desteklemek ) tuşları ( , değerleri () , girişler () , bu yüzden ondan tüm anahtarları veya değerleri almak için bir yolu yoktur.

WeakMap yalnızca aşağıdaki yöntemlere sahiptir:

  • zayıfMap.get (anahtar)
  • zayıfMap.set (anahtar, değer)
  • zayıfMap.delete (anahtar)
  • zayıfMap.has (anahtar)

Bu, bir nesne diğer tüm referansları kaybetmiş gibi açıktır (yukarıdaki koddaki 'kullanıcı' gibi), o zaman otomatik olarak çöp olarak toplanacaktır. Ancak teknik olarak temizleme işleminin ne zaman gerçekleştiği tam olarak belirtilmemiştir.

JavaScript motoru buna karar verir. Bellek temizlemeyi hemen gerçekleştirmeyi veya beklemeyi ve daha sonra daha fazla silme olduğunda temizlemeyi yapmayı seçebilir. Bu nedenle, teknik olarak a'nın mevcut eleman sayısı WeakMapbilinmemektedir. Motor temizlemiş veya temizlememiş veya kısmen temizlemiş olabilir. Bu nedenle, tüm anahtarlara / değerlere erişen yöntemler desteklenmez.

Not: - WeakMap'in ana uygulama alanı ek bir veri depolamadır. Bir nesnenin çöp toplanana kadar önbelleğe alınması gibi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.