一、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>