В чем разница между ES6 Map и WeakMap?

Глядя на эту и эту MDN-страницы, кажется, что единственное различие между Maps и WeakMaps - отсутствующее свойство "size" для WeakMaps. Но так ли это? Какая разница между ними?

5 ответов

Решение

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

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

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

[И вот почему у них нет size собственность также]

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

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

Еще одно отличие:

Ключи WeakMaps имеют только тип Object. Примитивные типы данных в качестве ключей не допускаются (например, 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 (ключ)
  • weakMap.set (ключ, значение)
  • weakMap.delete (ключ)
  • weakMap.has (ключ)

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

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

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

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

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

Другие вопросы по тегам