ES6 Map和WeakMap有什么区别?

时间:2013-03-24 21:22:30

标签: javascript ecmascript-6 ecmascript-harmony weakmap

查看thisthis MDN页面,似乎地图和WeakMaps之间的唯一区别是缺少"尺寸" WeakMaps的财产。但这是真的吗?它们之间的区别是什么?

7 个答案:

答案 0 :(得分:81)

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

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}。垃圾收集器继续执行并从“WeakMap”中删除键b指针,并从内存中删除{y: 12}。但是在“Map”的情况下,垃圾收集器不会从“Map”中删除指针,也不会从内存中删除{x: 12}

总结:WeakMap允许垃圾收集器执行其任务但不允许执行Map。

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

答案 1 :(得分:63)

对某些人来说,下一个解释可能会更清楚。

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键后,我们仍然可以在地图中访问它。同时,删除WeakMap的k2键会将其从wm中删除,也可以通过引用将其删除。

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

答案 2 :(得分:45)

来自the very same page, section "Why Weak Map?"

  

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

     

由于引用较弱,WeakMap键不可枚举   (即没有方法给你一个密钥列表)。如果他们是,   该列表将取决于垃圾收集的状态,介绍   非确定性。

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

  

如果你想要一个按键列表,你应该   自己保养。还有一个ECMAScript proposal   旨在介绍不会使用弱的简单集和地图   引用并且可以枚举。

- 这将是"normal" Maps。在MDN上未提及,但在harmony proposal中,这些也有itemskeysvalues生成器方法并实现Iterator interface

答案 3 :(得分:32)

另一个区别(来源: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

答案 4 :(得分:3)

来自 Javascript.info

地图-如果我们在常规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]

与此类似,如果我们在常规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()

WeakMap –现在,如果我们使用对象作为键,并且对该对象没有其他引用,则会自动从内存(和地图)中删除该对象。

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

// john is removed from memory!

答案 5 :(得分:2)

javascript中的WeapMap不包含任何键或值,它只是使用唯一ID 操作键值并将属性定义为键对象。

因为它通过方法key将属性定义为Object.definePropert(),所以key不能是原始类型。

并且因为WeapMap实际上不包含键值对,所以我们无法获得weakmap的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;
})();

implementation

的参考

答案 6 :(得分:0)

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()< / em>,因此无法从中获取所有键或值。

WeakMap仅具有以下方法:

  • weakMap.get(key)
  • weakMap.set(键,值)
  • weakMap.delete(key)
  • weakMap.has(key)

很明显,好像一个对象丢失了所有其他引用(例如上面的代码中的“ user”),则该对象将被自动垃圾收集。但是从技术上讲,清理时并没有完全指定。

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

  

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