天天看點

ES6躬行記(17)——Map

一、Map

  Map類似于Object(對象),可用來存儲鍵值對,但需要通過SameValueZero算法保持鍵的唯一性。與Set一樣,在使用之前也得要執行個體化,如下代碼所示,構造函數Map()中的參數也是一個可選的可疊代對象,但此對象得是鍵值對的集合或兩列的二維數組。

new Map();                                //Map(0) {}
new Map([["name", "strick"], ["age", 28]]);    //Map(2) {"name" => "strick", "age" => 28}      

1)屬性和方法

  Map比Set多一個讀取方法:get(),并且寫入方法改成了set(),其它的屬性和方法在功能上基本都一緻,隻是有些參數在含義上略有不同,例如delete()的參數表示鍵而不是值。方法的具體使用,可參加下面的代碼。

var people = new Map();
//寫入和讀取
people.set("name", "strick").set("age", 28);  //Map(2) {"name" => "strick", "age" => 28}
people.get("name");                 //"strick"
people.size;                     //2
//周遊
[...people.keys()];            //["name", "age"]
[...people.values()];          //["strick", 28]
[...people.entries()];         //[["name", "strick"], ["age", 28]]
/*
  "strick" "name" Map(2) {"name" => "strick", "age" => 28}
  28 "age" Map(2) {"name" => "strick", "age" => 28}
*/
people.forEach(function(value, index, map) {
  console.log(value, index, map);
});
//移除
people.delete("name")
people.has("name");           //false
people.clear();
people.has("age");            //false      

2)比較對象

  本節開篇就提到Map和Object很類似,但其實兩者之間還是有一些很重要的差別,具體如表10所列。

表10  Map和Object的對比

不同點 Map Object
所有類型,甚至包括NaN 字元串或Symbol類型
可疊代對象
尺寸 通過size屬性得到 需要手動計算
原型
寫入 set()方法 等号運算符
讀取 get()方法 成員通路運算符(點号或方括号)
移除 delete()或clear()方法 delete運算符
枚舉順序 根據鍵值對的添加順序 依照ES6的新規則

二、WeakMap

  WeakMap是Map的變體,也是鍵值對的集合,但它的鍵必須是弱引用的對象,并且不可枚舉,而值沒有限制,還是保持任意類型。當WeakMap的鍵所指的對象不再被引用時,其鍵和值将被GC自動回收。

1)建立和方法

  WeakSet也需要像Map那樣執行個體化(如下代碼所示),但沒有Map的size屬性,并且隻包含Map中的四個方法:set()、get()、has()和delete(),諸如清空和周遊相關的方法都是不存在的。

var weak = new WeakMap(),
  arr = [1];
weak.set(arr, 10);    //WeakMap {Array(1) => 10}
weak.get(arr);        //10
weak.has(arr);        //true
weak.delete(arr);
weak.has(arr);        //false      

2)用途

  WeakMap的主要優勢在于不幹擾垃圾收集,進而能夠有效的防止記憶體洩漏。它适用于隐藏資訊、存儲DOM節點等場景。下面是一個隐藏資訊的示例,privates變量是一個WeakMap,它的鍵是目前執行個體化的People對象,存儲的私有資料是一個對象,兩個原型方法分别用于寫入和讀取name屬性。

var people = (function() {
  var privates = new WeakMap();
  function People() {
    privates.set(this, {});     //初始化私有資料
  }
  People.prototype.setName = function(name) {
    privates.get(this).name = name;        //寫入
  };
  People.prototype.getName = function() {
    return privates.get(this).name;        //讀取
  };
  return new People();
})();
people.setName("strick");
people.getName();              //"strick"      

  這種存儲方式不僅能讓資料保持私有狀态,并且當與之關聯的對象執行個體被銷毀後,這些私有資料将被GC一并删除,進而釋放記憶體。

  下面是另一個存儲DOM節點的示例,node變量是一個WeakMap,它的鍵是文檔中的<div>元素(即DOM的一個節點),在該元素的事件處理程式中可更新digit屬性。當從文檔中移除該元素時,與之關聯的資料也會随之被删除。

<div id="container"></div>
<script>
    var container = document.getElementById("container");
    var node = new WeakMap();
    node.set(container, { digit: 0 });
    container.addEventListener("click", function() {
        var current = node.get(this);
        current.digit++;
        node.set(this, current);
      },
      false
    );
</script>