Глядя на эту и эту страницы MDN, кажется, что единственная разница между Картами и WeakMaps - это отсутствие свойства «размер» для WeakMaps. Но так ли это? В чем разница между ними?
key
не могут быть собраны, потому что на него ссылаются вы.
key
не могут быть собраны, потому что на него ссылаются вы.
Ответы:
С той же страницы, раздел « Почему слабая карта? » :
Опытный программист JavaScript заметит, что этот API может быть реализован в JavaScript с двумя массивами (один для ключей, один для значений), общих для 4 методов API. Такая реализация имела бы два основных неудобства. Первый - это поиск за O (n) (n - количество ключей на карте). Второй - проблема с утечкой памяти. С помощью карт, написанных вручную, массив ключей будет содержать ссылки на ключевые объекты, предотвращая их сборку мусора. В собственном WeakMaps ссылки на ключевые объекты хранятся «слабо» , что означает, что они не предотвращают сборку мусора в случае, если не будет другой ссылки на объект.
Из-за того, что ссылки слабые, ключи WeakMap нельзя перечислить (т. Е. Нет метода, дающего вам список ключей). Если бы это было так, список зависел бы от состояния сборки мусора, что привело бы к недетерминированности.
[И поэтому у них тоже нет size
собственности]
Если вы хотите иметь список ключей, вам следует вести его самостоятельно. Существует также предложение ECMAScript, направленное на введение простых наборов и карт, которые не будут использовать слабые ссылки и будут перечисляемыми.
- которые были бы «нормальными» Map
s . Не упоминается в MDN, но в предложении гармонии , те также items
, keys
и values
методы генератора и реализовать Iterator
интерфейс .
new Map().get(x)
что время поиска примерно такое же, как и при чтении свойства из простого объекта?
WeakMap
все еще имеет массив (или другую коллекцию) записей, он просто сообщает сборщику мусора, что это слабые ссылки .
Оба они ведут себя по-разному, когда объект, на который ссылаются их ключи / значения, удаляется. Возьмем приведенный ниже пример кода:
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/
map.entries().next().value // [{x:12}, 1]
WeakMap
может иметь только непримитивные ключи (без строк, чисел или Symbol
s в качестве ключей, только массивы, объекты, другие карты и т. Д.).
Map
но не вWeakMap
Возможно, следующее объяснение будет для кого-то более понятным.
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, это просто ссылки на другие объекты.
forEach
, (key, val)
должно быть на самом деле(val, key)
Еще одно отличие (источник: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
Ключи WeakMaps относятся только к типу Object. Примитивные типы данных в качестве ключей не допускаются (например, символ не может быть ключом WeakMap).
Также нельзя использовать строку, число или логическое значение в качестве WeakMap
ключа. A 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!
WeapMap в javascript не содержит никаких ключей или значений, он просто манипулирует значением ключа, используя уникальный идентификатор, и определяет свойство для ключевого объекта.
поскольку он определяет свойство key object
по методу Object.definePropert()
, ключ не должен быть примитивного типа .
а также из-за того, что WeapMap фактически не содержит пар ключ-значение, мы не можем получить свойство length для 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;
})();
ссылка на реализацию
id
запрограммированный код, но он должен быть уникальным за счет использования чего-то Math.random и Date.now () и т. Д. И добавив этот динамический идентификатор, можно решить первую проблему. Не могли бы вы дать мне решение по последним двум пунктам.
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 имеет только следующие методы:
Это очевидно, как если бы объект потерял все другие ссылки (например, «пользователь» в приведенном выше коде), он должен быть автоматически собран в мусор. Но технически точно не указано, когда произойдет очистка.
Это решает движок JavaScript. Он может выбрать немедленную очистку памяти или подождать и выполнить очистку позже, когда произойдет еще несколько удалений. Итак, технически текущее количество элементов WeakMap
неизвестно. Двигатель мог очистить его или нет, или сделал это частично. По этой причине методы, которые обращаются ко всем ключам и значениям, не поддерживаются.
Примечание: - Основная область применения WeakMap - дополнительное хранилище данных. Это похоже на кеширование объекта, пока этот объект не будет собран сборщиком мусора.