Глядя на это и this страницы MDN кажется, что единственная разница между Maps и WeakMaps заключается в отсутствующем свойстве "размер" для WeakMaps. Но так ли это? В чем разница между ними?
В чем разница между картой ES6 и WeakMap?
Ответы (7)
Из та же страница, раздел " Почему слабая карта?":
Опытный программист на JavaScript заметит, что этот API может быть реализован на JavaScript с двумя массивами (один для ключей, один для значений), общими для 4 методов API. Такая реализация будет иметь два основных неудобства. Первый — это поиск O(n) (n — количество ключей на карте). Вторая проблема связана с утечкой памяти. С картами, написанными вручную, массив ключей будет содержать ссылки на ключевые объекты, предотвращая их сборку мусора. В нативных WeakMaps ссылки на ключевые объекты хранятся "слабо", что означает, что они не предотвращают сборку мусора в случае отсутствия других ссылок на объект.
Из-за слабых ссылок ключи WeakMap не перечислимы (т. е. нет метода, дающего вам список ключей). Если бы они были, список зависел бы от состояния сборки мусора, вводя недетерминизм.
[И именно поэтому у них нет свойства size
]
Если вы хотите иметь список ключей, вы должны вести его самостоятельно. Существует также предложение ECMAScript, направленное на введение простых наборов и карт, которые не использовать слабые ссылки и быть перечислимыми.
‐ это будет "нормальный" Map
s. Не упоминается в MDN, но в предложении по гармонии они также имеют items
, keys
и values
методы генератора и реализуют Iterator
интерфейс.
new Map().get(x)
имеет примерно такое же время поиска, как чтение свойства из простого объекта?
- person Alexander Mills; 05.05.2018
WeakMap
все еще имеет массив (или другую коллекцию) записей, он просто сообщает сборщику мусора, что это слабые ссылки.
- person Bergi; 17.05.2018
Они оба ведут себя по-разному, когда объект, на который ссылаются их ключи/значения, удаляется. Давайте возьмем приведенный ниже пример кода:
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]
- person Bergi; 29.05.2015
WeakMap
может иметь только не примитивные ключи (без строк или чисел или Symbol
в качестве ключей, только массивы, объекты, другие карты и т. д.).
- person Ahmed Fasih; 28.08.2016
{x: 12}
и {y: 12}
. - Но {x: 12}
все еще находится в Map
, как вы продолжаете объяснять.
- person nnnnnn; 05.05.2017
Map
, но не в WeakMap
- person Alexander Derck; 02.08.2017
{}
или function() {}
.
- person vaughan; 05.11.2017
Может быть, следующее объяснение будет для кого-то более понятным.
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)
- person Miguel Mota; 20.01.2017
Еще одно отличие (источник: 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
Из 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 слабой карты.
а также управляемое значение присваивается обратно ключевому объекту, сборщик мусора легко может собрать ключ, если он не используется.
Пример кода для реализации.
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 () и т. д. И добавив этот динамический идентификатор, можно решить первую точку. Не могли бы вы дать мне решение для последних двух пунктов.
- person Ravi Sevta; 13.07.2020
Ключи 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 — дополнительное хранилище данных. Например, кэширование объекта до тех пор, пока этот объект не будет собран мусором.
key
невозможно собрать, так как на него ссылаетесь вы. - person John Dvorak   schedule 25.03.2013map
используются толькоweakMap
методы. - person John Dvorak   schedule 25.03.2013Map
иWeakMap
. Это было задавался в другом месте, но этот вопрос был закрыт как дубликат этого. Однако ни один из текущих ответов на этот вопрос не касается производительности. - person qntm   schedule 19.02.2018