简体   繁体   English

ES6 Map 和 WeakMap 有什么区别?

[英]What's the difference between ES6 Map and WeakMap?

Looking this and this MDN pages it seems like the only difference between Maps and WeakMaps is a missing "size" property for WeakMaps.查看这个这个MDN 页面,似乎 Maps 和 WeakMaps 之间的唯一区别是 WeakMaps 缺少“大小”属性。 But is this true?但这是真的吗? What's the difference between them?它们之间有什么区别?

They both behave differently when a object referenced by their keys/values gets deleted.当它们的键/值引用的对象被删除时,它们的行为都不同。 Lets take the below example code:让我们看下面的示例代码:

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

The above IIFE is executed there is no way we can reference {x: 12} and {y: 12} anymore.上面的 IIFE 执行后,我们无法再引用{x: 12}{y: 12} Garbage collector goes ahead and deletes the key b pointer from “WeakMap” and also removes {y: 12} from memory.垃圾收集器继续从“WeakMap”中删除键 b 指针,并从内存中删除{y: 12} But in case of “Map”, the garbage collector doesn't remove a pointer from “Map” and also doesn't remove {x: 12} from memory.但是在“Map”的情况下,垃圾收集器不会从“Map”中删除指针,也不会从内存中删除{x: 12}

Summary: WeakMap allows garbage collector to do its task but not Map.总结: WeakMap 允许垃圾收集器完成它的任务,但不允许 Map。

References: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/参考资料: http : //qnimate.com/difference-between-map-and-weakmap-in-javascript/

Maybe the next explanation will be more clear for someone.也许下一个解释对某人来说会更清楚。

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

As you see, after removing k1 key from the memory we can still access it inside the map.如您所见,从内存中删除k1密钥后,我们仍然可以在地图内访问它。 At the same time removing k2 key of WeakMap removes it from wm as well by reference.同时删除 WeakMap 的k2键也通过引用从wm删除它。

That's why WeakMap hasn't enumerable methods like forEach, because there is no such thing as list of WeakMap keys, they are just references to another objects.这就是为什么 WeakMap 没有像 forEach 这样的可枚举方法,因为没有 WeakMap 键列表这样的东西,它们只是对另一个对象的引用。

From the very same page, section " Why Weak Map? " :同一页面,“为什么地图? ”部分

The experienced JavaScript programmer will notice that this API could be implemented in JavaScript with two arrays (one for keys, one for values) shared by the 4 API methods.有经验的 JavaScript 程序员会注意到,这个 API 可以在 JavaScript 中实现,其中两个数组(一个用于键,一个用于值)由 4 个 API 方法共享。 Such an implementation would have two main inconveniences.这样的实施将有两个主要不便之处。 The first one is an O(n) search (n being the number of keys in the map).第一个是 O(n) 搜索(n 是映射中的键数)。 The second one is a memory leak issue.第二个是内存泄漏问题。 With manually written maps, the array of keys would keep references to key objects, preventing them from being garbage collected.使用手动编写的映射,键数组将保留对键对象的引用,防止它们被垃圾收集。 In native WeakMaps, references to key objects are held "weakly" , which means that they do not prevent garbage collection in case there would be no other reference to the object.在本机 WeakMap 中,对关键对象的引用是“弱”持有的,这意味着它们不会阻止垃圾收集,以防没有对该对象的其他引用。

Because of references being weak, WeakMap keys are not enumerable (ie there is no method giving you a list of the keys).由于引用较弱,WeakMap 键不可枚举(即没有方法为您提供键列表)。 If they were, the list would depend on the state of garbage collection, introducing non-determinism.如果是,则列表将取决于垃圾收集的状态,从而引入不确定性。

[And that's why they have no size property as well] [这就是为什么它们也没有size属性的原因]

If you want to have a list of keys, you should maintain it yourself.如果你想要一个键列表,你应该自己维护它。 There is also an ECMAScript proposal aiming at introducing simple sets and maps which would not use weak references and would be enumerable.还有一个ECMAScript 提案旨在引入不使用弱引用且可枚举的简单集合和映射。

‐ which would be the "normal" Map s . - 这将是“正常”的Map Not mentioned at MDN, but in the harmony proposal , those also have items , keys and values generator methods and implement the Iterator interface .在 MDN 中没有提到,但在和谐提案中,那些也有itemskeysvalues生成器方法并实现Iterator接口

Another difference (source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):另一个区别(来源: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):

Keys of WeakMaps are of the type Object only. WeakMap 的键只有 Object 类型。 Primitive data types as keys are not allowed (eg a Symbol can't be a WeakMap key).不允许使用原始数据类型作为键(例如 Symbol 不能是 WeakMap 键)。

Nor can a string, number, or boolean be used as a WeakMap key.字符串、数字或布尔值也不能用作WeakMap键。 A Map can use primitive values for keys. 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

From Javascript.info来自Javascript.info

Map -- If we use an object as the key in a regular Map, then while the Map exists, that object exists as well. Map——如果我们在常规 Map 中使用一个对象作为键,那么当 Map 存在时,该对象也存在。 It occupies memory and may not be garbage collected.它占用内存,可能不会被垃圾收集。

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]

Similar to that, if we use an object as the key in a regular Map, then while the Map exists, that object exists as well.与此类似,如果我们在常规 Map 中使用一个对象作为键,那么当 Map 存在时,该对象也存在。 It occupies memory and may not be garbage collected占用内存,可能不会被垃圾回收

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 -- Now, if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically. WeakMap——现在,如果我们使用一个对象作为其中的键,并且没有对该对象的其他引用——它将自动从内存(和映射)中删除。

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

// john is removed from memory!

WeapMap in javascript does not hold any keys or values, it just manipulates key value using a unique id and define a property to the key object. javascript 中的 WeapMap 不保存任何键或值,它只是使用唯一的 id操作键值并为键对象定义一个属性。

because it define property to key object by method Object.definePropert() , key must not be primitive type .因为它通过方法Object.definePropert()key object定义属性,所以key 不能是原始类型

and also because WeapMap does not contain actually key value pairs, we cannot get length property of weakmap.并且因为 WeapMap 实际上并不包含键值对,所以我们无法获得weakmap 的长度属性。

and also manipulated value is assigned back to the key object, garbage collector easily can collect key if it in no use.并且还将操纵的值分配回键对象,垃圾收集器可以轻松地收集不使用的键。

Sample code for implementation.实现的示例代码。

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

reference ofimplementation 实施参考

WeakMap keys must be objects, not primitive values. 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

Why????为什么????

Let's see below example.让我们看看下面的例子。

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

If we use an object as the key in a regular Map , then while the Map exists, that object exists as well.如果我们在常规Map使用一个对象作为键,那么当Map存在时,该对象也存在。 It occupies memory and may not be garbage collected.它占用内存,可能不会被垃圾收集。

WeakMap is fundamentally different in this aspect. WeakMap在这方面WeakMap根本的不同。 It doesn't prevent garbage-collection of key objects.它不会阻止关键对象的垃圾收集。

let user = { name: "User" };

let weakMap = new WeakMap();
weakMap.set(user, "...");

user = null; // overwrite the reference

// 'user' is removed from memory!

if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically.如果我们使用一个对象作为其中的键,并且没有对该对象的其他引用——它将自动从内存(和映射)中删除。

WeakMap does not support iteration and methods keys() , values() , entries() , so there's no way to get all keys or values from it. WeakMap支持迭代和方法keys()values()entries() ,因此无法从中获取所有键或值。

WeakMap has only the following methods: WeakMap 只有以下方法:

  • weakMap.get(key) weakMap.get(key)
  • weakMap.set(key, value) weakMap.set(key, value)
  • weakMap.delete(key) weakMap.delete(key)
  • weakMap.has(key) weakMap.has(key)

That is obvious as if an object has lost all other references (like 'user' in the code above), then it is to be garbage-collected automatically.这很明显,就好像一个对象丢失了所有其他引用(如上面代码中的“用户”),然后它会被自动垃圾收集。 But technically it's not exactly specified when the cleanup happens.但从技术上讲,它并没有完全指定何时进行清理。

The JavaScript engine decides that. JavaScript 引擎决定了这一点。 It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen.它可以选择立即执行内存清理,或者在发生更多删除时等待并稍后进行清理。 So, technically the current element count of a WeakMap is not known.因此,从技术上讲, WeakMap的当前元素数是未知的。 The engine may have cleaned it up or not or did it partially.发动机可能已经清理或未清理或部分清理。 For that reason, methods that access all keys/values are not supported.因此,不支持访问所有键/值的方法。

Note:- The main area of application for WeakMap is an additional data storage.注意:- WeakMap 的主要应用领域是额外的数据存储。 Like caching an object until that object gets garbage collected.就像缓存一个对象,直到该对象被垃圾收集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM