年末了,都回家過年了,是時候好好談談對象了。今天要談的對象是Map和WeakMap。先對這兩個對象進行一個簡單的介紹總結:數組
Map
的 key 能夠是任何類型的值,Object
的鍵值只能是 string 和 symbols。Map
實例按照插入的順序存儲數據Map
實例的屬性更容易刪除WeakMap
相比 Map
提供了更優的垃圾回收機制下面進入正題。數據結構
看下 MDN 解釋:函數
The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.ui
關鍵詞:鍵值對、按插入順序有序排列、鍵或者值能夠爲任何類型的數據。spa
語法code
new Map([iterable])
cdn
咱們再看一下 Map
實例上的屬性和方法。對象
初始化一個 Map 實例:blog
const map = new Map(); // 空的 Map
map.set(1, "first");
map.get(1); // 'first'
const newMap = new Map([
[1, "zhangsan"],
[2, "lisi"]
]);
newMap.get(1); // "zhangsan"
newMap.get(2); // "lisi"
複製代碼
對象裏的鍵值只能爲字符串。而 Map
實例如上解釋能夠爲任何類型的數據。three
const obj = {};
obj[1] = "one";
obj["1"]; // one
obj[1]; // one
const map = new Map();
map.set(1, "one");
map.set("1", "another one");
// map 包含2組鍵值對: 1, 'one' 以及 '1', 'another one'
複製代碼
這裏再說一下,Map
實例當在比較鍵名的時候採用 sameValueZero 的規則,有點像嚴格等於 ===
,但又有兩個例外:NaN 和 NaN、+0 和-0,Map 認爲它們同樣。
另外,Map 實例還支持鏈式調用設置鍵值對,對象只能一次設置一個鍵值對:
const map = new Map();
map
.set(1, "one")
.set(2, "two")
.set(3, "three");
複製代碼
刪除對象上的屬性值時會一直返回 true,除非這個屬性是
刪除一個 Map
上的屬性時,若是這個屬性存在會返回 true,若是不存在則返回 false。
// 刪除對象屬性
const obj = {
name: "zhangsan"
};
delete obj.name; // true
delete obj.age; // true,不存在這個屬性一樣會返回 true
// 刪除Map屬性
const map = new Map();
map.set("name", "zhangsan");
map.delete("name"); // true
map.delete("age"); // false
複製代碼
若是刪除對象上全部的屬性呢?或許能夠這樣:
const obj = { 1: 234 };
obj = {};
複製代碼
可是這樣的話,你其實只是把一個新的空對象複製給這個實例,而原先的舊對象並不必定就被刪除了(要看垃圾回收機制),若是別的地方對它還有引用,那它就還會一直存在。
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
delete obj[key];
}
}
複製代碼
Map
實例就能很好地處理這個問題:map.clear();
。
如開頭 MDN
上的解釋同樣, Map
的遍歷更好預測。
const obj = {};
obj[5] = "five";
obj[4] = "four";
Object.entries(obj); // [ ['4', 'four'], ['5', "five"] ]
const map = new Map();
map
.set(5, "five")
.set(4, "four")
.entries(); // [ 5 => "five", 4 => "four" ]
複製代碼
和對象相似,Map
也有 3 種方法用於遍歷對象:
map.keys()
返回鍵名組成的數組map.values()
返回鍵值組成的數組map.entries()
返回包含一組組鍵值對的可遍歷的數組Map
構造函數接收一個數組或者可迭代(iterable
)對象,因此對象轉 Map
實例的時候咱們能夠用 Object.entries
方法處理:
const obj = {
one: 1,
two: 2
};
const map = new Map(Object.entries(obj));
console.log(map.get("one")); // 1
複製代碼
那麼又如何把 Map
實例轉成對象呢?還好咱們有 Object.fromEntries
方法,用法和 Object.entries
相反:
const map = new Map();
map.set("one", 1);
map.set("two", 2);
const obj = Object.fromEntries(map);
console.log(obj.one); // 1
複製代碼
WeakMap
與 Map
相似,主要的不一樣點有兩處:
WeakMap
的只接受對象做爲鍵名。const map = new WeakMap();
map.set(1, 2);
// TypeError: Invalid value used as weak map key
map.set({}, 1);
複製代碼
WeakMap
鍵名所指向的對象,不計入垃圾回收機制。let obj = { name: "Matt" }; // object can be accessed
let map = new Map();
map.set(obj, true);
obj = null; // 儘管對象被重寫了,可是舊對象依然能夠在map裏訪問到
複製代碼
WeakMap
是怎麼處理這種狀況的:
let obj = { name: "Matt" };
let weakMap = new WeakMap();
weakMap.set(obj, true);
obj = null; // 重寫對象,同時也會在 weakMap 裏被刪除
// weakMap 如今是空
複製代碼
WeakMap
只有四種方法:get
, set
, delete
, has
。 之因此沒有 size
等屬性或者方法,就是由於這個機制, WeakMap
實例的長度可能會隨時變化,因此從規則上就禁止去訪問 WeakMap
的 size
屬性,天然也不會提供用於遍歷的那幾個屬性了。
從一些共同點以及不一樣點介紹了對象以及 Map
的特性,但願能幫助到你瞭解他們的優缺點,進而在適合的場景選用適合的數據結構。