ES6 Map和WeakMap有什么区别?

Dmi*_*rin 83 javascript ecmascript-harmony weakmap ecmascript-6

看看这个这个 MDN页面,似乎地图和WeakMaps之间的唯一区别是WeakMaps缺少"大小"属性.但这是真的吗?他们之间有什么区别?

ksh*_*ish 85

当它们的键/值引用的对象被删除时,它们的行为都不同.让我们采取以下示例代码:

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);
})()
Run Code Online (Sandbox Code Playgroud)

上述IIFE执行是没有办法,我们可以参考{x: 12}{y: 12}了.垃圾收集器继续并从"WeakMap"中删除键b指针,并{y: 12}从内存中删除.但是在"Map"的情况下,垃圾收集器不会从"Map"中删除指针,也不会{x: 12}从内存中删除.

简介:WeakMap允许垃圾收集器执行其任务但不允许执行Map.

参考文献:http://qnimate.com/difference-between-map-and-weakmap-in-javascript/

  • 为什么不从内存中删除?因为你仍然可以参考它!`map.entries().next().value // [{x:12},1]` (11认同)
  • 它不是一个自我调用的函数.它是一个立即调用的函数表达式.http://benalman.com/news/2010/11/immediately-invoked-function-expression/ (4认同)
  • @MuhammadUmer:对象只能有字符串“键”,而“WeakMap”只能有非原始键(没有字符串或数字或“Symbol”作为键,只有数组、对象、其他映射等)。 (2认同)
  • @nnnnnn 是的,这就是区别,它仍然在“Map”中,但不在“WeakMap”中 (2认同)

Rax*_*ter 66

也许下一个解释对某些人来说会更清楚.

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
Run Code Online (Sandbox Code Playgroud)

如您所见,k1从内存中删除密钥后,我们仍然可以在地图中访问它.同时删除k2WeakMap的键wm也可以通过引用将其删除.

这就是为什么WeakMap没有像forEach这样的可枚举方法,因为没有WeakMap键列表,它们只是对另一个对象的引用.

  • 当然,在最后一行中,wm.get(null)将是未定义的. (9认同)
  • 比从mozilla网站复制和粘贴更好的答案,赞誉. (7认同)
  • 令人难以置信的是,一个毫无意义的例子怎么会得到如此多的支持 (3认同)
  • 在`forEach`中,`(key,val)`实际上应该是`(val,key)` (2认同)

Ber*_*rgi 47

同一页面" 为什么地图? "部分:

经验丰富的JavaScript程序员会注意到,这个API可以用JavaScript实现,它有4个API方法共享的两个数组(一个用于键,一个用于值).这样的实施将有两个主要的不便之处.第一个是O(n)搜索(n是地图中的键数).第二个是内存泄漏问题.使用手动编写的映射,密钥数组将保留对密钥对象的引用,从而防止它们被垃圾回收.在本机WeakMaps中,对关键对象的引用保持"弱",这意味着它们不会阻止垃圾收集,以防没有对该对象的其他引用.

由于引用很弱,WeakMap键不可枚举(即没有方法为您提供键列表).如果是,那么列表将取决于垃圾收集的状态,引入非确定性.

[这就是他们没有size财产的原因]

如果你想要一个密钥列表,你应该自己维护.还有一个ECMAScript提案 旨在引入简单的集合和映射,这些集合和映射不会使用弱引用并且可以枚举.

- 这将是"正常" Map.在MDN中没有提到,但在和声提案中,那些也有items,keys并且values生成器方法和实现Iterator接口.


Tre*_*xon 33

另一个区别:

WeakMaps的键仅为Object类型.不允许将原始数据类型作为键(例如,Symbol不能是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
Run Code Online (Sandbox Code Playgroud)

  • 如果有人想知道:我可以想象这背后的原因是:你不能保留或传递对原始类型的引用.因此,WeakMap中的关键是它唯一的参考.这样就不可能进行垃圾收集.我不知道弱引用是不可能还是只是没有意义.但无论哪种方式,关键都需要是可以被弱引用的东西. (5认同)

小智 7

来自Javascript.info

Map——如果我们在常规 Map 中使用一个对象作为键,那么当 Map 存在时,该对象也存在。它占用内存,可能不会被垃圾收集。

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]
Run Code Online (Sandbox Code Playgroud)

与此类似,如果我们在常规 Map 中使用一个对象作为键,那么当 Map 存在时,该对象也存在。占用内存,可能不会被垃圾回收

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()
Run Code Online (Sandbox Code Playgroud)

WeakMap——现在,如果我们使用一个对象作为其中的键,并且没有对该对象的其他引用——它将自动从内存(和映射)中删除。

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

// john is removed from memory!
Run Code Online (Sandbox Code Playgroud)


Pra*_*iya 6

WeakMap键必须是对象,而不是原始值。

\n\n
let weakMap = new WeakMap();\n\nlet obj = {};\n\nweakMap.set(obj, "ok"); // works fine (object key)\n\n// can\'t use a string as the key\nweakMap.set("test", "Not ok"); // Error, because "test" is not an object\n
Run Code Online (Sandbox Code Playgroud)\n\n

为什么????

\n\n

让我们看下面的例子。

\n\n
let user = { name: "User" };\n\nlet map = new Map();\nmap.set(user, "...");\n\nuser = null; // overwrite the reference\n\n// \'user\' is stored inside the map,\n// We can get it by using map.keys()\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

如果我们使用一个对象作为常规 中的键Map,那么当 \n Map存在时,该对象也存在。它占用内存并且可能不会被垃圾收集。

\n\n

WeakMap在这方面有着根本的不同。它不会阻止关键对象的垃圾收集。

\n
\n\n
let user = { name: "User" };\n\nlet weakMap = new WeakMap();\nweakMap.set(user, "...");\n\nuser = null; // overwrite the reference\n\n// \'user\' is removed from memory!\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

如果我们使用一个对象作为其中的键,并且没有其他\n对该对象的引用\xe2\x80\x93,它将自动从内存(以及映射)中删除。

\n
\n\n

WeakMap 支持迭代和方法keys()values()entries(),因此\xe2\x80\x99s无法从中获取所有键或值。

\n\n

WeakMap 只有以下方法:

\n\n
    \n
  • 弱映射.get(key)
  • \n
  • weakMap.set(键, 值)
  • \n
  • weakMap.delete(key)
  • \n
  • weakMap.has(key)
  • \n
\n\n

很明显,如果一个对象丢失了所有其他引用(例如上面代码中的“user”),那么它将被自动垃圾收集。但从技术上讲,它\xe2\x80\x99s 并没有在清理发生时准确指定。

\n\n

JavaScript 引擎决定了这一点。它可以选择立即执行内存清理,或者等待更多删除发生后再进行清理。因此,从技术上讲,a 的当前元素计数WeakMap是未知的。发动机可能已清理或未清理或部分清理。因此,不支持访问所有键/值的方法。

\n\n
\n

注意:- WeakMap 的主要应用领域是附加数据存储。就像缓存一个对象直到该对象被垃圾回收一样。

\n
\n