看这个和这个 MDN页面,似乎Maps和WeakMaps之间的唯一区别是WeakMaps缺少了“ size”属性。但这是真的吗?它们之间有什么区别?
key
无法收集,因为它已被您引用。
key
无法收集,因为它已被您引用。
Answers:
有经验的JavaScript程序员会注意到,可以用JavaScript来实现此API,该API可以使用4种API方法共享的两个数组(一个用于键,一个用于值)。这样的实现将有两个主要的不便之处。第一个是O(n)搜索(n是地图中键的数量)。第二个是内存泄漏问题。对于手动编写的地图,键数组将保留对键对象的引用,以防止被垃圾回收。在本机WeakMaps中,对关键对象的引用被“弱地”保留,这意味着在没有其他对象引用的情况下,它们不会阻止垃圾回收。
由于引用弱,因此WeakMap密钥不可枚举(即,没有方法可以为您提供密钥列表)。如果是这样,则该列表将取决于垃圾收集的状态,从而引入不确定性。
[这就是为什么他们也没有size
财产的原因]
如果要有一个键列表,则应自己维护。还有一个ECMAScript提案 旨在引入简单的集合和映射,这些集合和映射将不使用弱引用并且是可枚举的。
-这将是“正常” Map
的。在MDN中没有提到,但是在协调提议中,那些也有items
,keys
以及values
生成器方法和实现Iterator
接口。
new Map().get(x)
具有与从普通对象读取属性大约相同的查找时间?
当它们的键/值引用的对象被删除时,它们的行为都不同。让我们看下面的示例代码:
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/
map.entries().next().value // [{x:12}, 1]
WeakMap
只能具有非原始键(不能将字符串或数字或Symbol
s作为键,只能使用数组,对象,其他映射等)。
Map
但不在WeakMap
也许对某人来说,下一个解释会更清楚。
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)
另一个区别(来源:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap):
WeakMap的键仅属于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]
与此类似,如果我们在常规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!
JavaScript中的WeapMap不保存任何键或值,它只是使用唯一的ID来操纵键值,并为键对象定义一个属性。
因为keykey object
通过method 定义属性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;
})();
实施参考
id
,但这应该通过使用Math.random和Date.now()等来唯一。通过添加此动态id,可以解决第一点。您能否为我提供最后两点的解决方案。
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()
如果我们将一个对象用作Regular中的键
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(),entry(),因此无法从中获取所有键或值。
WeakMap仅具有以下方法:
这很明显,就好像一个对象丢失了所有其他引用(例如上面的代码中的“ user”)一样,那么该对象将被自动垃圾回收。但是从技术上讲,清理时并没有确切指定。
JavaScript引擎决定了这一点。当发生更多删除操作时,它可以选择立即执行内存清理,或者等待并稍后进行清理。因此,技术上a的当前元素计数WeakMap
未知。引擎可能已经清理过或没有清理过或部分清理过。因此,不支持访问所有键/值的方法。
注意: -WeakMap的主要应用领域是额外的数据存储。就像将对象缓存到该对象被垃圾回收一样。