javascript ES6 Map 和 WeakMap 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15604168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 01:23:01  来源:igfitidea点击:

What's the difference between ES6 Map and WeakMap?

javascriptecmascript-6ecmascript-harmonyweakmap

提问by Dmitrii Sorin

Looking thisand thisMDN pages it seems like the only difference between Maps and WeakMaps is a missing "size" property for WeakMaps. But is this true? What's the difference between them?

查看这个这个MDN 页面,似乎 Maps 和 WeakMaps 之间的唯一区别是 WeakMaps 缺少“大小”属性。但这是真的吗?它们之间有什么区别?

采纳答案by Bergi

From the very same page, section "Why WeakMap?":

来自同一页面的“ Why WeakMap?”部分

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

Because of references being weak, WeakMap keys are not enumerable (i.e. there is no method giving you a list of the keys). If they were, the list would depend on the state of garbage collection, introducing non-determinism.

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

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

[And that's why they have no sizeproperty as well]

[这就是为什么他们也没有size财产的原因]

If you want to have a list of keys, you should maintain it yourself. There is also an ECMAScript proposalaiming at introducing simple sets and maps which would not use weak references and would be enumerable.

如果你想要一个键列表,你应该自己维护它。还有一个ECMAScript 提案旨在引入不使用弱引用且可枚举的简单集合和映射。

‐ which would be the "normal" Maps. Not mentioned at MDN, but in the harmony proposal, those also have items, keysand valuesgenerator methods and implement the Iteratorinterface.

- 这将是“正常” Maps。在 MDN 中没有提到,但是在和谐提案中,那些也有itemskeysvalues生成器方法并实现Iterator接口

回答by kshirish

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. Garbage collector goes ahead and deletes the key b pointer from “WeakMap” and also removes {y: 12}from memory. But in case of “Map”, the garbage collector doesn't remove a pointer from “Map” and also doesn't remove {x: 12}from memory.

上面的 IIFE 被执行了,我们无法再参考{x: 12}{y: 12}了。垃圾收集器继续从“WeakMap”中删除键 b 指针,并{y: 12}从内存中删除。但是在“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/

回答by Rax Wunter

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 k1key from the memory we can still access it inside the map. At the same time removing k2key of WeakMap removes it from wmas well by reference.

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

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 键列表这样的东西,它们只是对另一个对象的引用。

回答by Trevor Dixon

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. Primitive data types as keys are not allowed (e.g. a Symbol can't be a WeakMap key).

WeakMap 的键只有 Object 类型。不允许使用原始数据类型作为键(例如 Symbol 不能是 WeakMap 键)。

Nor can a string, number, or boolean be used as a WeakMapkey. A Mapcanuse primitive values for keys.

字符串、数字或布尔值也不能用作WeakMap键。AMap可以对键使用原始值。

w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key

m = new Map
m.set('a', 'b'); // Works

回答by Ravi Sevta

WeapMap in javascript does not hold any keys or values, it just manipulate key value using a unique idand define property to key object.

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

because it define property to keyby method Object.definePropert(), key must not be primitive type.

因为它key通过 method定义属性Object.definePropert(),所以 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 key, 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 of implementation

实施参考

回答by Pravin Divraniya

WeakMapkeys 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 Mapexists, that object exists as well. It occupies memory and may not be garbage collected.

WeakMapis fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects.

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

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

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.

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

WeakMapdoes notsupport 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.set(key, value)
  • weakMap.delete(key)
  • weakMap.has(key)
  • weakMap.get(key)
  • weakMap.set(key, value)
  • weakMap.delete(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. 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 WeakMapis not known. 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.

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

Note:-The main area of application for WeakMap is an additional data storage. Like caching an object until that object gets garbage collected.

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