JavaScript中Object、map、weakmap的區(qū)別分析
前言
ECMAScript 6以前,在JavaScript中實(shí)現(xiàn)“鍵/值”式存儲可以使用Object來方便高效地完成,也就是使用對象屬性作為鍵,再使用屬性來引用值。但這種實(shí)現(xiàn)并非沒有問題,為此TC39委員會專門為“鍵/值”存儲定義了一個規(guī)范。作為ECMAScript 6的新增特性,Map是一種新的集合類型,為這門語言帶來了真正的鍵/值存儲機(jī)制。Map的大多數(shù)特性都可以通過Object類型實(shí)現(xiàn),但二者之間還是存在一些細(xì)微的差異。具體實(shí)踐中使用哪一個,還是值得細(xì)細(xì)甄別。
一、map 的使用
初始化
object 可以使用字面量、構(gòu)造函數(shù)、Object.crate的形式創(chuàng)建。而map 只能通過new 關(guān)鍵字和構(gòu)造函數(shù)創(chuàng)建。對于map如果想在創(chuàng)建的同時初始化實(shí)例,可以給Map構(gòu)造函數(shù)傳入一個可迭代對象,需要包含鍵/值對數(shù)組??傻鷮ο笾械拿總€鍵/值對都會按照迭代順序插入到新映射實(shí)例中:
object 的創(chuàng)建方式
const object = {}
const object1 = new Object()
const object2 = Object.create({})
map 的創(chuàng)建方式
//使用new關(guān)鍵字
const m0 = new Map;
// 使用嵌套數(shù)組初始化映射
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m1.size); // 3
// 使用自定義迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function*() {
yield ["key1", "val1"];
yield ["key2", "val2"];
yield ["key3", "val3"];
}
});
alert(m2.size); // 3
// 映射期待的鍵/值對,無論是否提供
const m3 = new Map([[]]);
alert(m3.has(undefined)); // true
alert(m3.get(undefined)); // undefined
map鍵類型
與Object只能使用數(shù)值、字符串或符號作為鍵不同,Map可以使用任何JavaScript數(shù)據(jù)類型作為鍵。Map內(nèi)部使用SameValueZero比較操作(ECMAScript規(guī)范內(nèi)部定義,語言中不能使用),基本上相當(dāng)于使用嚴(yán)格對象相等的標(biāo)準(zhǔn)來檢查鍵的匹配性。與Object類似,映射的值是沒有限制的。
const m = new Map();
const functionKey = function() {};
const symbolKey = Symbol();
const objectKey = new Object();
m.set(functionKey, "functionValue");
m.set(symbolKey, "symbolValue");
m.set(objectKey, "objectValue");
alert(m.get(functionKey)); // functionValue
alert(m.get(symbolKey)); // symbolValue
alert(m.get(objectKey)); // objectValue
// SameValueZero比較意味著獨(dú)立實(shí)例不沖突
alert(m.get(function() {})); // undefined
順序與迭代
與Object類型的一個主要差異是,Map實(shí)例會維護(hù)鍵值對的插入順序,因此可以根據(jù)插入順序執(zhí)行迭代操作。映射實(shí)例可以提供一個迭代器(Iterator),能以插入順序生成[key,value]形式的數(shù)組??梢酝ㄟ^entries()方法(或者Symbol.iterator屬性,它引用entries())取得這個迭代器:
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
二、選擇Object還是Map
對于多數(shù)Web開發(fā)任務(wù)來說,選擇Object還是Map只是個人偏好問題,影響不 大。不過,對于在乎內(nèi)存和性能的開發(fā)者來說,對象和映射之間確實(shí)存在顯著的 差別。
1.內(nèi)存占用
Object和Map的工程級實(shí)現(xiàn)在不同瀏覽器間存在明顯差異,但存儲單個鍵/值對所占用的內(nèi)存數(shù)量都會隨鍵的數(shù)量線性增加。批量添加或刪除鍵/值對則取決于各瀏覽器對該類型內(nèi)存分配的工程實(shí)現(xiàn)。不同瀏覽器的情況不同,但給定固定大小的內(nèi)存,Map大約可以比Object多存儲50%的鍵/值對。
2.插入性能
向Object和Map中插入新鍵/值對的消耗大致相當(dāng),不過插入Map在所有瀏覽器中一般會稍微快一點(diǎn)兒。對這兩個類型來說,插入速度并不會隨著鍵/值對數(shù)量而線性增加。如果代碼涉及大量插入操作,那么顯然Map的性能更佳。
3.查找速度
與插入不同,從大型Object和Map中查找鍵/值對的性能差異極小,但如果只包含少量鍵/值對,則Object有時候速度更快。在把Object當(dāng)成數(shù)組使用的情況下(比如使用連續(xù)整數(shù)作為屬性),瀏覽器引擎可以進(jìn)行優(yōu)化,在內(nèi)存中使用更高效的布局。這對Map來說是不可能的。對這兩個類型而言,查找速度不會隨著鍵/值對數(shù)量增加而線性增加。如果代碼涉及大量查找操作,那么某些情況下可能選擇Object更好一些。
4.刪除性能
使用delete刪除Object屬性的性能一直以來飽受詬病,目前在很多瀏覽器中仍然如此。為此,出現(xiàn)了一些偽刪除對象屬性的操作,包括把屬性值設(shè)置為undefined或null。但很多時候,這都是一種討厭的或不適宜的折中。而對大多數(shù)瀏覽器引擎來說,Map的delete()操作都比插入和查找更快。如果代碼涉及大量刪除操作,那么毫無疑問應(yīng)該選擇Map
三、weakMap
ECMAScript 6新增的“弱映射”(WeakMap)是一種新的集合類型,為這門語言帶來了增強(qiáng)的鍵/值對存儲機(jī)制。WeakMap是Map的“兄弟”類型,其API也是Map的子集。WeakMap中的“weak”(弱),描述的是JavaScript垃圾回收程序?qū)Υ叭跤成洹敝墟I的方式。
weakcMap 的弱
WeakMap中“weak”表示弱映射的鍵是“弱弱地拿著”的。意思就是,這些鍵不屬于正式的引用,不會阻止垃圾回收,當(dāng)瀏覽器需要回收內(nèi)存時這些鍵是可能會被回收的。但要注意的是,弱映射中值的引用可不是“弱弱地拿著”的。只要鍵存在,鍵/值對就會存在于映射中,并被當(dāng)作對值的引用,因此就不會被當(dāng)作垃圾回收。
//會被回收
const wm = new WeakMap();
wm.set({}, "val");
//不會被回收
const wm2 = new WeakMap();
const container = {
key: {}
};
wm2.set(container.key, "val");
function removeReference() {
container.key = null;
}
在vm中,set()方法初始化了一個新對象并將它用作一個字符串的鍵。因?yàn)闆]有指向這個對象的其他引用,所以當(dāng)這行代碼執(zhí)行完成后,這個對象鍵就會被當(dāng)作垃圾回收。然后,這個鍵/值對就從弱映射中消失了,使其成為一個空映射。在這個例子中,因?yàn)橹狄矝]有被引用,所以這對鍵/值被破壞以后,值本身也會成為垃圾回收的目標(biāo)。
而在vm1中,container對象維護(hù)著一個對弱映射鍵的引用,因此這個對象鍵不會成為垃圾回收的目標(biāo)。不過,如果調(diào)用了removeReference(),就會摧毀鍵對象的最后一個引用,垃圾回收程序就可以把這個鍵/值對清理掉。
weakMap使用
WeakMap的初始化與map并沒有什么太大的差別,需要注意的是weakMap只能使用object類型的鍵,這與weakMap的作用是息息相關(guān)的
const key1 = {id: 1},
key2 = {id: 2},
key3 = {id: 3};
// 使用嵌套數(shù)組初始化弱映射
const wm1 = new WeakMap([
[key1, "val1"],
[key2, "val2"],
[key3, "val3"]
]);
alert(wm.get(key1)); // val1
alert(wm.get(key2)); // val2
alert(wm.get(key3)); // val3
// 原始值可以先包裝成對象再用作鍵
const stringKey = new String("key1");
const wm3 = new WeakMap([
stringKey, "val1"
]);
alert(wm3.get(stringKey)); // "val1"
四、使用weakMap的場景
WeakMap實(shí)例與現(xiàn)有JavaScript對象有著很大不同,可能一時不容易說清楚應(yīng)該怎么使用它。這個問題沒有唯一的答案,但已經(jīng)出現(xiàn)了很多相關(guān)策略。
DOM節(jié)點(diǎn)元數(shù)據(jù)
因?yàn)閃eakMap實(shí)例不會妨礙垃圾回收,所以非常適合保存關(guān)聯(lián)元數(shù)據(jù)。如以下代碼所示,下面的例子使用的是WeakMap,當(dāng)節(jié)點(diǎn)從DOM樹中被刪除后,垃圾回收程序就可以立即釋放其內(nèi)存(假設(shè)沒有其他地方引用這個對象):
const wm = new WeakMap();
const loginButton = document.querySelector('#login');
// 給這個節(jié)點(diǎn)關(guān)聯(lián)一些元數(shù)據(jù)
wm.set(loginButton, {disabled: true});
總結(jié)
以上就是object、map、weakmap的相關(guān)使用和區(qū)別了。其實(shí)在大多數(shù)情況下,object和map使用是沒有什么區(qū)別的,但是如果你需要大量的插入和查找刪除,或者需要使用對象作為鍵值的話,使用map是比較優(yōu)的選擇。另外weakMap在使用的對象可能會被動態(tài)刪除的情況下,比map具有優(yōu)化內(nèi)存的優(yōu)勢。
以上就是JavaScript中Object、map、weakmap的區(qū)別分析的詳細(xì)內(nèi)容,更多關(guān)于JavaScript中Object、map、weakmap區(qū)別的資料請關(guān)注腳本之家其它相關(guān)文章!
- JavaScript中利用Array和Object實(shí)現(xiàn)Map的方法
- Springboot通過ObjectMapper配置json序列化詳解
- 使用ObjectMapper把Json轉(zhuǎn)換為復(fù)雜的實(shí)體類
- JavaScript 中有了Object 為什么還需要 Map 呢
- JavaScript?Map?和?Object?的區(qū)別解析
- JavaScript中Map與Object應(yīng)用場景
- JS中Map、WeakMap和Object的區(qū)別解析
- Javascript中Object和Map之間的轉(zhuǎn)換方法
- 面試???js中 Map和 Object 的區(qū)別小結(jié)
相關(guān)文章
boostrap模態(tài)框二次彈出清空原有內(nèi)容的方法
今天小編就為大家分享一篇boostrap模態(tài)框二次彈出清空原有內(nèi)容的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Input文本框隨著輸入內(nèi)容多少自動延伸的實(shí)現(xiàn)
下面小編就為大家?guī)硪黄狪nput文本框隨著輸入內(nèi)容多少自動延伸的實(shí)現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
JS清除字符串中重復(fù)值的實(shí)現(xiàn)方法
這篇文章主要介紹了JS清除字符串中重復(fù)值的實(shí)現(xiàn)方法,涉及javascript數(shù)組與字符串的遍歷、比較及數(shù)學(xué)運(yùn)算相關(guān)技巧,需要的朋友可以參考下2016-08-08
利用JS判斷字符串是否含有數(shù)字與特殊字符的方法小結(jié)
在我們?nèi)粘9ぷ鞯臅r候,利用javaScript判斷一個字符串中是否包括有數(shù)字和"-",在一些表單提交的地方,這是比較有用的常規(guī)判斷,這里收集有幾種不同的方法,最后還將簡要介紹下isNAN函數(shù)的使用方法和例子,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-11-11

