您的位置:首页 > 其它

[译]ECMAScript 6中的集合类型,第三部分:WeakMap

2012-11-07 18:00 176 查看
原文:http://www.nczonline.net/blog/2012/11/06/ecmascript-6-collections-part-3-weakmaps/

WeakMap
类似于常规的
Map
的一点是,它们都是把一个值映射到某个唯一的键上,然后就可以使用这个键获取到与之对应的值.
WeakMap
Map
不同的地方是,它的键只能是对象值而不可以是原始值.虽然这个限制看起来很奇怪,但正是这一点,才让
WeakMap
变得很有价值.

一个
WeakMap
对象的键只持有其所引用对象的弱引用,弱引用的特点是,它不能阻止垃圾回收器回收其引用的对象.当那个对象被垃圾回收器销毁后,
WeakMap
对象中引用它的那个键值对也会被删除.使用
WeakMap
最典型的例子就是用在要创建一个与特定的DOM元素相关联的对象的时候.例如,jQuery在程序内部维护着一些对象的缓存,每个缓存引用着一个DOM元素.使用
WeakMap
的话,jQuery就可以在某些DOM元素被从文档中删除后就自动释放它们先前占用的内存.

ECMAScript 6中的
WeakMap
类型是一个无序的键值对列表,键必须是一个非null的对象(non-null object),值可以是任意类型.
WeakMap
的API很简单,和
Map
一样,
set()
get()
分别用来添加数据和获取数据:

var map = new WeakMap(),
element = document.querySelector(".element");

map.set(element, "Original");

// 下面就可以使用了
var value = map.get(element);
console.log(value);             // "Original"

// 下面删除引用
element.parentNode.removeChild(element);
element = null;

//译者注:下面这句实际上会报错(value is not a non-null object),因为键必须是非null的对象.作者只是为了讲解,看下面.
value = map.get(element);
console.log(value);             // undefined


在这个例子中,我们存储了一个键值对.键是一个DOM元素,存储着一个对应的字符串值.随后把那个DOM元素传入
get()
方法来获取到存储的字符串值.如果这个DOM元素被从文档中删除了,指向它的变量也被赋值为
null
,然后
WeakMap
对象中的那个键值对会被自动删除,这时如果再读取那个键值对的话,就会失败.

这个例子有点误导,因为在第二次调用
map.get(element)
的时候,实际上是把
null
(
element
被赋的值)而不是DOM元素的引用传进去了.你不能使用
null
来作为
WeakMap
对象的键(WeakMap的键只能是对象,null不是对象),这样的代码是会抛出异常的,根本不会执行到console.log语句.上面的代码之所以那么写,只是为了讲解.想要说明那个键值对已经不存在了.不过不幸的是,我们没有任何办法来检测这个键值对是否真的被删除了(因为
element
的值已经是
null
,我们无法获取到指向那个DOM元素的引用了,假如真能获取到那个DOM对象的引用,传给get方法的话,应该返回undefined).


译者注:由于语文水平实在有限,上面的这段话我无法表达清楚.所以我用我拙劣的水平做了几张图,希望我的理解是对的,也希望你能看懂.

var map = new WeakMap(),
element = document.querySelector(".element");

变量map和element各自引用了一个对象.



map.set(element, "Original");

map中添加了一个键值对,这个键和变量element同时指向一个DOM对象,只是一个是强引用,一个是弱引用.



element.parentNode.removeChild(element);
element = null;

强引用全部主动断掉,最后剩下的弱引用也自动断掉,孤立的DOM元素被回收,WeakMap对象中对应的键值对被自动清除.如果是常规的Map,由于不是弱引用,所以那个DOM对象不会被回收,仍然存在,仍然可以通过get()方法访问到.




WeakMap
对象还有一个
has()
方法,可以判断某个对象引用是否作为了自己的键,还有
delete()
方法,用来删除一个键值对.

var map = new WeakMap(),
element = document.querySelector(".element");map.set(element, "Original");
console.log(map.has(element)); // true
console.log(map.get(element)); // "Original"

map.delete(element);
console.log(map.has(element)); // false
console.log(map.get(element)); // undefined


使用
delete()
方法删除某个键后,再执行
has()
方法的时候会返回
false
,执行
get()
方法会返回
undefined
.

浏览器支持

Firefox和Chrome都已经实现了
WeakMap
,可是,在Chrome中,你必须手动开启ECMAScript 6特性:打开
chrome://flags
勾选"启用实验性 JavaScript".目前浏览器的实现都完全遵循了当前的strawman[1]规范(而ECMAScript 6的最新草案新添加了一个
WeakMap.prototype.clear()
方法,这两个浏览器目前还都没实现).

用途和限制

目前
WeakMap
有一个特定的使用情境,那就是在将值映射到一些未来可能被会删除的对象上的时候.
WeakMap
的这种"能释放某些无用对象所占用的内存的能力"对于那种将DOM元素包装成为某种自定义对象的JavaScript库来说是很有用的(比如jQuery和YUI).在未来,
WeakMap
的标准完全实现且被广泛使用之后,应该会有更多的能用到
WeakMap
的地方,所以在短期内,不要因为想不到使用
WeakMap
的好点子而苦恼.

在大多数情况下,使用常规的
Map
应该是你最合适的选择.
WeakMap
有不少限制,比如不能枚举键值对(
for of
),也不能得知它们到底包含了多少个键值对(
size
).如果你需要这样做,那么就使用常规的
Map
.如果你仅仅需要把一些对象作为键,且不需要其他更多的功能,那么
WeakMap
是个好的选择.

参考

WeakMapsStrawman (ECMA)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐