原來(lái),Map 的真相居然是 ...

大家好政基,我是這波能反殺瓦糕,一名光榮的十年老前端。

這兩天腋么,我已經(jīng)麻了。

當(dāng)我準(zhǔn)備集中精力完成《React 知命境》的時(shí)候亥揖,一個(gè)不起眼的小問(wèn)題珊擂,幽幽的復(fù)現(xiàn)在我的眼前。

我的第一反應(yīng)费变,這么簡(jiǎn)單的問(wèn)題摧扇,想要用的時(shí)候就用唄。

但是... ... 不對(duì)挚歧,在我模糊的印象中扛稽,這個(gè)人能力挺強(qiáng),常年看我的文章滑负,對(duì)基礎(chǔ)的研究比較深入在张,不會(huì)問(wèn)那么隨便的問(wèn)題,搞不好我這樣敷衍了之后矮慕,還會(huì)被引出下一個(gè)問(wèn)題帮匾,我得回答專業(yè)一點(diǎn),穩(wěn)住我十年老油子的高大人設(shè)才行痴鳄。

根據(jù)我的預(yù)判瘟斜,她一定是想問(wèn)什么時(shí)候用 Object,什么時(shí)候用 Map,在 JavaScript 的使用者中螺句,有此疑問(wèn)的不在少數(shù)虽惭。于是我就開(kāi)始在記憶中搜索關(guān)于這兩個(gè)對(duì)象的區(qū)別。

ObjectMap 都可以存儲(chǔ)鍵值對(duì)蛇尚。

Objectkey 值只能是數(shù)字芽唇、字符串,symbol佣蓉。Map 的key值可以是任意數(shù)據(jù)類型披摄。

Map 是可迭代對(duì)象,Object 不可以迭代勇凭。

Map 會(huì)記錄屬性的寫(xiě)入順序疚膊,Object 不會(huì)記錄寫(xiě)入的先后順序甚至還有可能會(huì)排序。

Map 有 size 屬性虾标,而 Object 沒(méi)有寓盗。

那什么時(shí)候用 MapObject 更合適呢?

額... ... 糟糕璧函,想不起來(lái)傀蚌!

CPU 單線程運(yùn)轉(zhuǎn)了五分鐘,還是想不起來(lái)蘸吓。不過(guò)沒(méi)關(guān)系善炫,我還有萬(wàn)能的百度,我輸入關(guān)鍵字库继,開(kāi)始搜索箩艺,我很快就能得到答案。

果然百度大法好宪萄,搜索結(jié)果里有大量的文章在分析他們艺谆,頭一條是掘金的一篇譯文,一看就比較靠譜拜英,于是滿懷期待的點(diǎn)進(jìn)去静汤,開(kāi)始閱讀這篇文章。

文章在分析了大量的各自的特點(diǎn)之后居凶,終于看到了我想要的內(nèi)容虫给,Map 的應(yīng)用場(chǎng)景。

然而讀著讀著侠碧,好像有點(diǎn)不太對(duì)勁狰右。更多的還是一些特性的分析,例如 Map 的刪除操作性能更好舆床,存儲(chǔ)大數(shù)更合適棋蚌,并沒(méi)有介紹任何具體的場(chǎng)景嫁佳。

而且還出現(xiàn)了一些我不太認(rèn)同的小疑問(wèn)。

好吧谷暮,這篇文章沒(méi)有我找到的答案蒿往,如法炮制,我開(kāi)始閱讀別的文章湿弦。

然而... 大多數(shù)都是雷同的信息瓤漏。

我依稀記得之前使用 Map 解決過(guò)一個(gè)非常棒的案例,可就是想不起來(lái)颊埃,加上搜索無(wú)望蔬充,我不免有些心急。

時(shí)間已經(jīng)不知不覺(jué)過(guò)去了 10 分鐘班利,我還沒(méi)有回復(fù)那個(gè)尊稱我為“波神”的小妹妹饥漫。我已經(jīng)感受到了,我的大佬人設(shè)正在逐漸崩塌罗标。

對(duì)哦庸队,我可太蠢了,既然我之前使用過(guò)闯割,把項(xiàng)目代碼拿出來(lái)搜索一下不就找到了嗎彻消?

看到了希望的曙光,我進(jìn)入了修改緊急 bug 的高效狀態(tài)宙拉。迅速打開(kāi) vs code宾尚,打開(kāi)我的項(xiàng)目代碼,全局搜索 new Map谢澈。

哈哈煌贴,果然找到了大量使用 Map 的代碼。

可是當(dāng)我點(diǎn)開(kāi)代碼之后澳化,才發(fā)現(xiàn).... 居然沒(méi)有熟悉感。全都不是我想要的場(chǎng)景稳吮。

這樣的情況缎谷,用 {} 不更簡(jiǎn)單嗎?

這肯定不是我寫(xiě)的代碼灶似。

真正的大師列林,永遠(yuǎn)懷著一顆學(xué)徒的心。

我實(shí)在想不起來(lái)以前那個(gè)非常適合用 Map 的場(chǎng)景了酪惭,搜索找不到希痴,代碼也找不到,好在我還有幾個(gè)大廠大佬眾多春感,且非称龃矗活躍的技術(shù)群虏缸。

于是我問(wèn).

我再問(wèn).

這個(gè)問(wèn)題在幾個(gè)群都引發(fā)了激烈的討論,我就像一個(gè)小白瘋狂的吸收著大佬們的知識(shí)嫩实。大佬之間的討論就是不一樣刽辙,很快我們就撇開(kāi)了毫無(wú)意義的表面特性,開(kāi)始聊起了性能甲献。

有個(gè)字節(jié)的大佬拋出一個(gè)觀點(diǎn)宰缤,他說(shuō),對(duì)象的讀取沒(méi)有 Map 快晃洒,所以他幾乎都是能用 Map 的地方就會(huì)用 Map慨灭。

另一個(gè)大佬認(rèn)為在速度上 Map 比 Object 并沒(méi)有明顯優(yōu)勢(shì),在刪除屬性時(shí) Map 表現(xiàn)更好一點(diǎn)球及。

我又想到了剛才看的掘金的文章氧骤,說(shuō)是 Object 的讀寫(xiě)速度更快,幾個(gè)結(jié)論說(shuō)法不一桶略,于是討論陷入了驗(yàn)證階段语淘。

如果這個(gè)事情能夠得到論證的話,那么「能用 Map 的地方就使用 Map」 就是一個(gè)非常完美的答案际歼。

為了證明這個(gè)事情惶翻,我開(kāi)始考慮一個(gè)事情,Object 在內(nèi)存中到底是如何存儲(chǔ)的鹅心?Map 又是如何存儲(chǔ)的呢吕粗?

我依稀記得 V8 對(duì) Object 的處理是有優(yōu)化手段的,但是年代久遠(yuǎn)記不清晰了旭愧,于是有了新的方向颅筋,我再次踏上了尋找資料的征途。再次祭出百度输枯。

果然不出我所料议泵。

V8 對(duì)對(duì)象屬性的存儲(chǔ)結(jié)構(gòu)并沒(méi)有表面上那么簡(jiǎn)單,有特殊的處理桃熄。

在掘金和知乎的文章里先口,我找到這個(gè)圖。

一個(gè)對(duì)象里有快屬性和快屬性的區(qū)分瞳收。當(dāng)屬性數(shù)量較少時(shí)「in-object properties」碉京,或者 key 為數(shù)字類型「elements」,此時(shí)會(huì)采用快屬性螟深,快屬性使用線性結(jié)構(gòu)存儲(chǔ)谐宙。所以讀取屬性的速度是非常快的界弧。當(dāng)屬性變多凡蜻,為了確保新增和刪除的效率搭综,此時(shí)會(huì)啟用慢屬性「properties」,采用詞典鍵值對(duì)的方式存儲(chǔ)屬性內(nèi)容咽瓷。

我知道设凹,很多人看到這里,肯定會(huì)疑問(wèn)什么是線性結(jié)構(gòu)茅姜,什么是非線性結(jié)構(gòu)闪朱,哈哈哈,還好我沒(méi)有疑問(wèn)钻洒。

也就是說(shuō)奋姿,從基礎(chǔ)理論上來(lái)看,Object 會(huì)因?yàn)閷傩詳?shù)量上分為兩個(gè)階段素标,從而解決 Object 的讀寫(xiě)問(wèn)題称诗,而且,V8 還為 Object 創(chuàng)建了隱藏類用于記錄每個(gè)屬性的偏移量头遭,也就意味著寓免,Object 的讀寫(xiě)不會(huì)太慢。

這個(gè)界限有的文章說(shuō)是10個(gè)计维,但是我使用開(kāi)發(fā)者工具的 Memery 記錄的 snapshot 驗(yàn)證的結(jié)果不是這樣

那么 Map 的存儲(chǔ)在內(nèi)存中又是什么結(jié)構(gòu)呢袜香?

哈哈,這個(gè)我知道鲫惶!

散列表 + 鏈表 + 紅黑樹(shù) = hashMap蜈首。

我突然就悟了。

也就是說(shuō)欠母,如果屬性數(shù)量偏小的情況下欢策,讀寫(xiě)速度上,Object 和 Map 應(yīng)該不會(huì)有太大的差別赏淌。而只有數(shù)據(jù)量非常大的時(shí)候踩寇,才會(huì)逐漸體現(xiàn)出來(lái)差別。那么這個(gè)數(shù)據(jù)量大六水,到底要達(dá)到什么程度呢俺孙?我也不確定。

寫(xiě)個(gè)案例缩擂,驗(yàn)證一下鼠冕。

首先驗(yàn)證一下寫(xiě)入的時(shí)間成本添寺。

// 先定義一個(gè)數(shù)量上限
const up = 9999

var mt1 = performance.now()
var map = new Map()
for(var i = 0; i < up; i++) {
  map.set(`f${i}`, {a: i, children: { a: i }})
}

console.log(`   Map: `, performance.now() - mt1)

var ot1 = performance.now()
var obj = {}

for (var i = 0; i < up; i++) {
  obj[`f${i}`] = {b: i, children: {a: i}}
}

console.log('Object: ', performance.now() - ot1)

刷新了 20 多次胯盯,基本上都在 5 ~ 10 ms 之間波動(dòng)。時(shí)間上誰(shuí)高誰(shuí)低沒(méi)有明確的差別计露。不過(guò) Object 比 Map 耗時(shí)更短的次數(shù)會(huì)多一點(diǎn)博脑。這符合我的預(yù)期憎乙。

接下來(lái)我組建調(diào)高 up 變量的值。繼續(xù)驗(yàn)證叉趣。當(dāng)我把 up 的值設(shè)置為 99999 時(shí)泞边,耗時(shí)上依然沒(méi)有明顯的差別。

當(dāng)我把 up 的值設(shè)置為 499999 時(shí)疗杉,Object 的寫(xiě)入速度才開(kāi)始穩(wěn)定的比 Map 耗時(shí)更長(zhǎng)阵谚。

好家伙,我從來(lái)不會(huì)維護(hù)這么大的數(shù)據(jù)量在項(xiàng)目中烟具。

接下來(lái)梢什,我又依次驗(yàn)證的讀取速度和刪除速度。

在刪除上朝聋,我把 up 的值設(shè)置為 199999 嗡午,Object 的刪除耗時(shí)才會(huì)穩(wěn)定的比 Map 慢。

// 刪除
for(var i = 0; i < up; i++) {
  map.delete(`f${i}`)
}

在讀取速度上冀痕,up 的值為 159999 時(shí) Object 的讀取速度會(huì)穩(wěn)定比 Map 慢荔睹。

// 訪問(wèn)
for (var i = 0; i < up; i++) {
  map.get(`f${i}`)
}

所以,在性能的表現(xiàn)上言蛇,新增僻他、刪除、讀取的速度猜极,在數(shù)量非常少時(shí)中姜,Object 的表現(xiàn)可能會(huì)稍微好那么一點(diǎn)點(diǎn)點(diǎn),甚至不太明顯能感知得出來(lái)跟伏。

而在數(shù)量非常大的時(shí)候丢胚,Map 的表現(xiàn)會(huì)比 Object 好∈馨猓可是這種程度的數(shù)量携龟,我想很難在項(xiàng)目中把數(shù)據(jù)維護(hù)到這種程度。

驗(yàn)證結(jié)果讓我居然神奇的發(fā)現(xiàn)勘高,上面兩位大佬不一樣的觀點(diǎn)峡蟋,居然都說(shuō)的過(guò)去。

能用 Map 就用 Map 华望,沒(méi)什么毛病蕊蝗。Object 也沒(méi)有比 Map 有什么明顯的速度優(yōu)勢(shì)。

當(dāng)我做完驗(yàn)證回過(guò)頭來(lái)看群消息的時(shí)候赖舟,另外一個(gè)群的大佬提供了一個(gè)非常牛逼的應(yīng)用場(chǎng)景蓬戚。那就是策略模式的封裝。

膜拜宾抓!

策略模式通常情況下都是一個(gè)鍵值對(duì)應(yīng)一個(gè)規(guī)則子漩。但是豫喧!在某些特殊場(chǎng)景下,會(huì)出現(xiàn)多個(gè)鍵值對(duì)應(yīng)一個(gè)規(guī)則的情況幢泼。這個(gè)時(shí)候紧显,Map 就有了用武之地。Map 支持正則表達(dá)式作為 key 值缕棵,這樣孵班,使用 Map 就可以存儲(chǔ)多對(duì)一的匹配規(guī)則。

折騰了一天招驴,我苦逼的發(fā)現(xiàn)重父,我終于想起來(lái)我之前用 Map 實(shí)現(xiàn)的那個(gè)應(yīng)用場(chǎng)景是什么了。

( |||)

那就是聊天列表和聊天內(nèi)容的實(shí)現(xiàn)忽匈。這個(gè)場(chǎng)景完美符合了 Map 的特性房午。

聊天內(nèi)容列表因?yàn)橐彺婧芏鄡?nèi)容,數(shù)據(jù)量夠大丹允,并且郭厌,聊天是一個(gè)頻繁變動(dòng)的場(chǎng)景。聊天列表有新消息就會(huì)重新排序雕蔽,聊天內(nèi)容也會(huì)頻繁的插入新的消息折柠,特別是群聊,對(duì)聊天內(nèi)容的順序也有嚴(yán)格的要求批狐。

數(shù)據(jù)量大扇售、頻繁寫(xiě)入、排序嚣艇、對(duì)寫(xiě)入順序有嚴(yán)格的要求承冰,這個(gè)場(chǎng)景使用 Map 來(lái)管理數(shù)據(jù)再合適不過(guò)了。

太棒了食零。有了這些東西困乒,我終于松了一口氣》∫ィ可以回復(fù)她了娜搂。

可是,當(dāng)我點(diǎn)開(kāi)聊天窗口的時(shí)候... ...

我是這波能反殺吱抚,關(guān)注我百宇,解鎖更多... ... 哎,算了...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秘豹,一起剝皮案震驚了整個(gè)濱河市携御,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖因痛,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異岸更,居然都是意外死亡鸵膏,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)怎炊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)谭企,“玉大人,你說(shuō)我怎么就攤上這事评肆≌椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵质况,是天一觀的道長(zhǎng)惜索。 經(jīng)常有香客問(wèn)我跋炕,道長(zhǎng),這世上最難降的妖魔是什么俄占? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮淆衷,結(jié)果婚禮上缸榄,老公的妹妹穿的比我還像新娘。我一直安慰自己祝拯,他們只是感情好甚带,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著佳头,像睡著了一般鹰贵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上康嘉,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天砾莱,我揣著相機(jī)與錄音,去河邊找鬼凄鼻。 笑死腊瑟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的块蚌。 我是一名探鬼主播闰非,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼峭范!你這毒婦竟也來(lái)了财松?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辆毡,沒(méi)想到半個(gè)月后菜秦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舶掖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年球昨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眨攘。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡主慰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鲫售,到底是詐尸還是另有隱情共螺,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布情竹,位于F島的核電站藐不,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏秦效。R本人自食惡果不足惜佳吞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望棉安。 院中可真熱鬧底扳,春花似錦、人聲如沸贡耽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蒲赂。三九已至阱冶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滥嘴,已是汗流浹背木蹬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留若皱,地道東北人镊叁。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像走触,于是被迫代替她去往敵國(guó)和親晦譬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容