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


原文:http://www.nczonline.net/blog/2012/11/06/ecmascript-6-collections-part-3-weakmaps/


WeakMap類似於常規的Map的一點是,它們都是把一個值映射到某個唯一的鍵上,然后就可以使用這個鍵獲取到與之對應的值.WeakMapMap不同的地方是,它的鍵只能是對象值而不可以是原始值.雖然這個限制看起來很奇怪,但正是這一點,才讓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是個好的選擇.

參考

  1. WeakMapsStrawman (ECMA)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM