Какая разница между ES6 Map и WeakMap?

В поисках этого и этих страниц MDN, похоже, единственная разница между Maps и WeakMaps отсутствует Свойство "размер" для WeakMaps. Но это правда? Какая разница между ними?

Ответ 1

Из на той же странице, раздел "Почему Слабая Карта?" :

Опытный JavaScript-программист заметит, что этот API мог бы быть реализован в JavaScript с двумя массивами (один для ключей, один для значения), разделяемые четырьмя API-методами. Такая реализация два основных неудобства. Первый - это поиск O (n) (n - количество ключей на карте). Второй - проблема утечки памяти. С помощью карт, написанных вручную, массив ключей будет содержать ссылки на ключевых объектов, предотвращая их сбор мусора. В родном WeakMaps, ссылки на ключевые объекты удерживаются "слабо" , что означает что они не предотвращают сбор мусора, если не будет другая ссылка на объект.

Из-за слабости ссылок ключи WeakMap не перечислимы (т.е. нет метода, дающего вам список ключей). Если бы они были, список будет зависеть от состояния сбора мусора, введения недетерминизм.

[И поэтому у них нет свойства size]

Если вы хотите иметь список ключей, вы должны поддерживайте это самостоятельно. Существует также ECMAScript предложениес целью введения простых множеств и карт, которые не использовали бы слабые ссылки и были бы перечислены.

- это будет "normal" Map s. Не упомянутые в MDN, но в соглашении гармонии, у них также есть методы items, keys и values генератора и реализованы Iterator интерфейс.

Ответ 2

Они ведут себя по-разному, когда объект, на который ссылаются их ключи/значения, удаляется. Давайте рассмотрим приведенный ниже код:

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}. Сборщик мусора идет вперед и удаляет указатель клавиши b из "WeakMap", а также удаляет {y: 12} из памяти. Но в случае "Карты" сборщик мусора не удаляет указатель с "Карты", а также не удаляет {x: 12} из памяти.

Сводка: WeakMap позволяет сборщику мусора выполнять свою задачу, но не Map.

Ссылки: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/

Ответ 3

Возможно, следующее объяснение будет более понятным для кого-то.

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, это просто ссылки на другие объекты.

Ответ 4

Другое отличие (источник: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap):

Ключи WeakMaps имеют только тип Object. Примитивные типы данных как ключи не разрешены (например, символ не может быть ключом 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

Ответ 5

Weapmap в javascript не содержит никаких ключей или значений, он просто манипулирует значением ключа с помощью уникального идентификатора и определяет свойство для ключевого объекта.

потому что он определяет свойство для key методом Object.definePropert(), ключ не должен быть примитивным типом.

а также потому, что WeapMap не содержит пары ключевых значений, мы не можем получить свойство 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;
})();

ссылка на реализацию

Ответ 6

Ключи 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 (), records(), поэтому нет возможности получить из нее все ключи или значения.

У WeakMap есть только следующие методы:

  • strongMap.get (ключ)
  • weakMap.set (ключ, значение)
  • weakMap.delete (ключ)
  • weakMap.has (ключ)

Это очевидно, как если бы объект потерял все другие ссылки (например, "пользователь" в приведенном выше коде), тогда он должен быть автоматически собран. Но технически это точно не указано, когда происходит очистка.

Механизм JavaScript решает это. Он может выполнить очистку памяти немедленно или подождать и выполнить очистку позже, когда произойдет больше удалений. Таким образом, технически текущее количество элементов в WeakMap неизвестно. Двигатель, возможно, очистил это или нет, или сделал это частично. По этой причине методы, которые обращаются ко всем ключам/значениям, не поддерживаются.

Примечание: - Основная область применения WeakMap - это дополнительное хранилище данных. Например, кэширование объекта до тех пор, пока этот объект не будет удален.