一文詳細(xì)說(shuō)一說(shuō)Map和WeakMap的區(qū)別(面試官常問(wèn))
一、Map vs WeakMap
| 特性 | Map | WeakMap |
|---|---|---|
| 鍵的類型 | 任意類型(基本類型 / 引用類型) | 僅支持引用類型(對(duì)象) |
| 鍵的引用特性 | 強(qiáng)引用:鍵對(duì)象不會(huì)被 GC 回收 | 弱引用:鍵對(duì)象無(wú)其他引用時(shí),會(huì)被 GC 自動(dòng)回收(鍵值對(duì)隨之消失) |
| 遍歷性 | 支持(keys ()/values ()/entries ()/forEach/for...of) | 不支持(無(wú)遍歷方法、無(wú) size 屬性) |
| 鍵的枚舉 / 獲取 | 可獲取所有鍵(如 Array.from (map.keys ())) | 無(wú)法獲取 / 枚舉所有鍵(無(wú) API) |
| 常用 API | set/get/has/delete/clear/size | set/get/has/delete(無(wú) clear/size) |
| 內(nèi)存占用 | 鍵對(duì)象未手動(dòng)刪除則一直占用 | 自動(dòng)回收無(wú)引用的鍵,內(nèi)存更友好 |
| 使用場(chǎng)景 | 需遍歷 / 枚舉、鍵為基本類型、長(zhǎng)期存儲(chǔ)鍵值對(duì) | 臨時(shí)關(guān)聯(lián)數(shù)據(jù)(如 DOM 元素→元數(shù)據(jù))、避免內(nèi)存泄漏 |
核心差異:弱引用
- Map 對(duì)鍵是強(qiáng)引用:即使鍵對(duì)象外部無(wú)引用,Map 仍持有該對(duì)象,GC 不會(huì)回收,可能導(dǎo)致內(nèi)存泄漏;
- WeakMap 對(duì)鍵是弱引用:鍵對(duì)象僅被 WeakMap 引用時(shí),GC 會(huì)回收該對(duì)象,同時(shí) WeakMap 中對(duì)應(yīng)的鍵值對(duì)也會(huì)被移除(無(wú)需手動(dòng)刪除)。
示例
// Map:強(qiáng)引用導(dǎo)致內(nèi)存泄漏風(fēng)險(xiǎn)
const map = new Map();
let obj = { id: 1 };
map.set(obj, "data");
obj = null; // 手動(dòng)置空,但map仍引用obj,GC不會(huì)回收
// WeakMap:弱引用自動(dòng)回收
const weakMap = new WeakMap();
let obj2 = { id: 2 };
weakMap.set(obj2, "data");
obj2 = null; // obj2無(wú)其他引用,GC回收后,weakMap中該鍵值對(duì)消失
二、Set vs WeakSet
| 特性 | Set | WeakSet |
|---|---|---|
| 值的類型 | 任意類型(基本類型 / 引用類型) | 僅支持引用類型(對(duì)象) |
| 值的引用特性 | 強(qiáng)引用:值對(duì)象不會(huì)被 GC 回收 | 弱引用:值對(duì)象無(wú)其他引用時(shí),會(huì)被 GC 自動(dòng)回收(值隨之移除) |
| 遍歷性 | 支持(keys ()/values ()/entries ()/forEach/for...of) | 不支持(無(wú)遍歷方法、無(wú) size 屬性) |
| 值的枚舉 / 獲取 | 可獲取所有值(如 Array.from (set)) | 無(wú)法獲取 / 枚舉所有值(無(wú) API) |
| 常用 API | add/has/delete/clear/size | add/has/delete(無(wú) clear/size) |
| 內(nèi)存占用 | 值對(duì)象未手動(dòng)刪除則一直占用 | 自動(dòng)回收無(wú)引用的值,內(nèi)存更友好 |
| 使用場(chǎng)景 | 需遍歷 / 枚舉、值為基本類型、存儲(chǔ)唯一值集合 | 存儲(chǔ)臨時(shí)對(duì)象(如 DOM 元素集合)、避免內(nèi)存泄漏 |
核心差異:弱引用
- Set 對(duì)值是強(qiáng)引用:值對(duì)象即使外部無(wú)引用,Set 仍持有,GC 不回收;
- WeakSet 對(duì)值是弱引用:值對(duì)象僅被 WeakSet 引用時(shí),GC 會(huì)回收該對(duì)象,WeakSet 中對(duì)應(yīng)的項(xiàng)也會(huì)被移除。
示例
// Set:強(qiáng)引用
const set = new Set();
let obj = { id: 1 };
set.add(obj);
obj = null; // set仍引用obj,GC不回收
// WeakSet:弱引用
const weakSet = new WeakSet();
let obj2 = { id: 2 };
weakSet.add(obj2);
obj2 = null; // obj2無(wú)其他引用,GC回收后,weakSet中該值消失
三、Map vs Set 區(qū)別(補(bǔ)充知識(shí))
Map 和 Set 都是 ES6 新增的有序集合(迭代順序?yàn)椴迦腠樞颍?/strong> ,均為強(qiáng)引用、支持遍歷、可存儲(chǔ)唯一值,但核心定位和數(shù)據(jù)結(jié)構(gòu)完全不同,以下是詳細(xì)對(duì)比:
| 特性 | Map | Set |
|---|---|---|
| 核心定位 | 鍵值對(duì)集合(鍵→值映射) | 值的集合(僅存儲(chǔ)唯一值,無(wú)鍵) |
| 存儲(chǔ)形式 | [key, value] 鍵值對(duì),鍵唯一、值可重復(fù) | 單個(gè)值(value),值必須唯一 |
| 重復(fù)判定規(guī)則 | 鍵唯一(NaN 視為相同,對(duì)象引用不同則視為不同) | 值唯一(規(guī)則同 Map 鍵的判定) |
| 核心 API(增) | set(key, value):按鍵存值 | add(value):添加值 |
| 核心 API(查) | get(key):按鍵取值;has(key):判斷鍵是否存在 | has(value):判斷值是否存在(無(wú) get) |
| 核心 API(刪) | delete(key):按鍵刪除鍵值對(duì) | delete(value):按值刪除項(xiàng) |
| 遍歷方式 | 可遍歷鍵(keys())、值(values())、鍵值對(duì)(entries()) | 可遍歷值(keys()/values() 等價(jià),entries() 返回 [value, value]) |
| 長(zhǎng)度 / 大小 | size 屬性:返回鍵值對(duì)數(shù)量 | size 屬性:返回唯一值數(shù)量 |
| 使用場(chǎng)景 | 1. 鍵值映射(如 ID→用戶信息)2. 需要通過(guò) “鍵” 快速查找 “值”3. 存儲(chǔ)關(guān)聯(lián)數(shù)據(jù) | 1. 存儲(chǔ)不重復(fù)的唯一值集合(如去重?cái)?shù)組)2. 僅需判斷 “值是否存在”3. 過(guò)濾重復(fù)數(shù)據(jù) |
1. Map:鍵值對(duì)存儲(chǔ)與查找
const map = new Map();
// 存:鍵唯一,值可重復(fù)
map.set("id1", { name: "張三" });
map.set("id2", { name: "李四" });
map.set("id1", { name: "張三2" }); // 覆蓋id1的舊值
// 查:按鍵取值
console.log(map.get("id1")); // { name: "張三2" }
console.log(map.has("id2")); // true
// 遍歷:鍵、值、鍵值對(duì)
for (const key of map.keys()) console.log(key); // id1、id2
for (const value of map.values()) console.log(value); // {name: "張三2"}、{name: "李四"}
for (const [k, v] of map.entries()) console.log(k, v);
2. Set:唯一值集合(無(wú)鍵)
const set = new Set(); // 存:值唯一,重復(fù)添加無(wú)效 set.add(1); set.add(2); set.add(1); // 無(wú)效果,1已存在 // 查:僅能判斷值是否存在,無(wú)get console.log(set.has(2)); // true // console.log(set.get(2)); // 報(bào)錯(cuò):Set 無(wú)get方法 // 遍歷:keys/values等價(jià),entries返回[值, 值] for (const val of set.values()) console.log(val); // 1、2 for (const [v1, v2] of set.entries()) console.log(v1, v2); // 1 1、2 2 // 典型場(chǎng)景:數(shù)組去重 const arr = [1, 2, 2, 3]; const uniqueArr = [...new Set(arr)]; // [1,2,3]
3.核心總結(jié)
| 維度 | Map | Set |
|---|---|---|
| 數(shù)據(jù)結(jié)構(gòu) | 鍵值對(duì)(字典) | 單值集合(集合) |
| 核心操作 | 按 “鍵” 存 / 取 / 刪 | 按 “值” 增 / 判 / 刪(無(wú)取值操作) |
| 重復(fù)處理 | 鍵唯一(值可重復(fù)) | 值唯一(無(wú)重復(fù)) |
| 核心用途 | 鍵值映射、關(guān)聯(lián)數(shù)據(jù)存儲(chǔ) | 去重、唯一值判斷 |
簡(jiǎn)單記:
- 需要 “通過(guò)一個(gè)標(biāo)識(shí)找對(duì)應(yīng)數(shù)據(jù)”→ 用 Map;
- 只需要 “存儲(chǔ)不重復(fù)的一組值,或判斷值是否存在”→ 用 Set。
三、通用總結(jié)
| 類型 | 核心特點(diǎn) | 適用場(chǎng)景 |
|---|---|---|
| Map/Set | 強(qiáng)引用、支持遍歷、鍵 / 值可存任意類型 | 需持久存儲(chǔ)、遍歷、鍵 / 值為基本類型的場(chǎng)景 |
| WeakMap/WeakSet | 弱引用、不支持遍歷、僅存引用類型 | 臨時(shí)關(guān)聯(lián)數(shù)據(jù)、避免內(nèi)存泄漏(如 DOM / 臨時(shí)對(duì)象) |
關(guān)鍵提醒:
WeakMap/WeakSet 無(wú)法遍歷 / 獲取 size,因?yàn)槠鋬?nèi)部數(shù)據(jù)會(huì)被 GC 動(dòng)態(tài)修改,無(wú)法保證數(shù)據(jù)的穩(wěn)定性;
而 Map/Set 是 “可預(yù)測(cè)” 的靜態(tài)集合(除非手動(dòng)修改)。
到此這篇關(guān)于Map和WeakMap區(qū)別的文章就介紹到這了,更多相關(guān)js Map和WeakMap區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js替換字符串中所有指定的字符(實(shí)現(xiàn)代碼)
下面小編就為大家?guī)?lái)一篇js替換字符串中所有指定的字符(實(shí)現(xiàn)代碼)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
詳解javascript中對(duì)數(shù)據(jù)格式化的思考
本篇文章主要介紹了詳解javascript中對(duì)數(shù)據(jù)文本格式化的思考 ,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01
js實(shí)現(xiàn)飛機(jī)大戰(zhàn)游戲
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)飛機(jī)大戰(zhàn)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
IntelliJ IDEA 安裝vue開(kāi)發(fā)插件的方法
本篇文章主要介紹了IntelliJ IDEA 安裝vue開(kāi)發(fā)插件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
JS防止網(wǎng)頁(yè)被嵌入iframe框架的方法分析
這篇文章主要介紹了JS防止網(wǎng)頁(yè)被嵌入iframe框架的方法,結(jié)合實(shí)例形式分析了針對(duì)不同瀏覽器防止網(wǎng)頁(yè)被嵌入框架的相關(guān)注意事項(xiàng)與操作技巧,需要的朋友可以參考下2016-09-09
javaScript合并對(duì)象的多種方式及知識(shí)擴(kuò)展
眾所周知JavaScript中有多種方法可以合并對(duì)象,下面這篇文章主要給大家介紹了關(guān)于javaScript合并對(duì)象的多種方式及知識(shí)擴(kuò)展,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
JS實(shí)現(xiàn)物體帶緩沖的間歇運(yùn)動(dòng)效果示例
這篇文章主要介紹了JS實(shí)現(xiàn)物體帶緩沖的間歇運(yùn)動(dòng)效果,可實(shí)現(xiàn)物體定時(shí)間歇運(yùn)動(dòng)的功能,涉及javascript定時(shí)器、數(shù)學(xué)運(yùn)算及頁(yè)面元素動(dòng)態(tài)修改的相關(guān)操作技巧,需要的朋友可以參考下2016-12-12
cocos creator Touch事件應(yīng)用(觸控選擇多個(gè)子節(jié)點(diǎn)的實(shí)例)
下面小編就為大家?guī)?lái)一篇cocos creator Touch事件應(yīng)用(觸控選擇多個(gè)子節(jié)點(diǎn)的實(shí)例)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就想給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09

