一文詳解JavaScript中使用對(duì)象數(shù)組、對(duì)象(字典)保存數(shù)據(jù)的區(qū)別
示例:
const products=[
{id:'aaa',name:'aname',overview:'aoverview'},
{id:'bbb',name:'bname',overview:'boverview'}
];
const products={
'aaa':{name:'aname',overview:'aoverview'},
'bbb':{name:'bname',overview:'boverview'}
};在 JavaScript 中存儲(chǔ)產(chǎn)品數(shù)據(jù),你給出的兩種方案分別使用了數(shù)組和對(duì)象(字典)。下面從多個(gè)角度分析它們的優(yōu)劣、運(yùn)行效率以及底層機(jī)制,以便你根據(jù)實(shí)際需求做出選擇。
1. 數(shù)據(jù)結(jié)構(gòu)概覽
// 方案一:數(shù)組
const productsArray = [
{ id: 'aaa', name: 'aname', overview: 'aoverview' },
{ id: 'bbb', name: 'bname', overview: 'boverview' }
];
// 方案二:對(duì)象(以 id 為鍵)
const productsObject = {
'aaa': { name: 'aname', overview: 'aoverview' },
'bbb': { name: 'bname', overview: 'boverview' }
};
2. 核心操作對(duì)比
| 操作 | 數(shù)組(productsArray) | 對(duì)象(productsObject) |
|---|---|---|
| 通過 id 查找 | 需要遍歷數(shù)組,時(shí)間復(fù)雜度 O(n) arr.find(p => p.id === id) | 直接通過鍵訪問,時(shí)間復(fù)雜度 O(1) obj[id] |
| 遍歷所有產(chǎn)品 | 直接使用 for、forEach 或 map,內(nèi)存連續(xù),速度快 | 需先獲取 Object.values(obj) 或 Object.keys(obj),產(chǎn)生臨時(shí)數(shù)組,稍慢 |
| 添加新產(chǎn)品 | push 在末尾追加,O(1)(無需移動(dòng)元素) | 直接賦值 obj[newId] = {...},O(1)(哈希表插入) |
| 刪除產(chǎn)品 | 若需保持順序,用 splice 會(huì)移動(dòng)后續(xù)元素,O(n) 若不關(guān)心順序,可標(biāo)記刪除 | 使用 delete obj[id],O(1),但可能導(dǎo)致對(duì)象進(jìn)入“慢模式” |
| 更新產(chǎn)品 | 先查找(O(n))再修改,或直接通過已知索引修改(O(1)) | 直接通過鍵修改 obj[id].name = 'new',O(1) |
| 按 id 排序/篩選 | 可直接用數(shù)組方法(sort, filter),方便靈活 | 需先轉(zhuǎn)為數(shù)組,再操作 |
3. 內(nèi)存占用
- 數(shù)組:每個(gè)元素都是一個(gè)對(duì)象,且內(nèi)部必須顯式存儲(chǔ)
id字段。如果有 N 個(gè)產(chǎn)品,就會(huì)存儲(chǔ) N 個(gè) id 字符串。 - 對(duì)象:id 作為鍵(key)存儲(chǔ),值對(duì)象中不再需要
id字段。因此節(jié)省了 N 個(gè) id 字符串的內(nèi)存(但鍵本身也占用內(nèi)存,通常比字符串值稍少,因?yàn)殒I被內(nèi)部化)。
總體而言,對(duì)象方案在內(nèi)存上略優(yōu),尤其當(dāng)數(shù)據(jù)量較大時(shí)差異更明顯。
4. JavaScript 引擎內(nèi)部運(yùn)作方式
數(shù)組(以 V8 引擎為例)
- 如果數(shù)組元素類型一致(例如都是對(duì)象),V8 會(huì)使用 PACKED_ELEMENTS 模式,元素在內(nèi)存中連續(xù)存儲(chǔ),訪問和迭代非常快,CPU 緩存利用率高。
- 當(dāng)數(shù)組長度變化(如
splice刪除中間元素),需要移動(dòng)后續(xù)元素,開銷較大。 - 引擎還會(huì)根據(jù)元素類型優(yōu)化(如數(shù)字?jǐn)?shù)組會(huì)用 C 語言級(jí)別的數(shù)組存儲(chǔ)),但這里存儲(chǔ)的是對(duì)象引用,所以仍是引用數(shù)組。
對(duì)象(字典)
V8 中對(duì)象有兩種表示模式:
- 快速屬性:當(dāng)對(duì)象屬性數(shù)量較少、且屬性名是確定的字符串時(shí),V8 會(huì)使用隱藏類(Hidden Class)和內(nèi)聯(lián)緩存(Inline Cache),屬性訪問接近 C 語言結(jié)構(gòu)體的速度。
- 慢速屬性(字典模式):當(dāng)屬性被頻繁動(dòng)態(tài)添加/刪除,或數(shù)量很多時(shí),V8 會(huì)將對(duì)象切換為哈希表實(shí)現(xiàn),此時(shí)訪問速度仍然 O(1),但常數(shù)因子較大,且內(nèi)存占用增加。
你的 productsObject 鍵是動(dòng)態(tài)的(每個(gè)產(chǎn)品 id 都可能不同),且數(shù)量可能較多,很可能最終以哈希表形式存儲(chǔ)。但通過 id 訪問依然非常快。
5. 實(shí)際使用中的優(yōu)劣總結(jié)
方案一:數(shù)組
優(yōu)點(diǎn):
- 保持順序(按插入順序或排序后順序),適合列表展示。
- 遍歷方便,可直接用數(shù)組迭代方法。
- 與 React/Vue 等框架的列表渲染完美配合(通常需要傳遞數(shù)組)。
缺點(diǎn):
- 通過 id 查找效率低(需要遍歷或額外建立索引)。
- 刪除中間元素成本高(
splice移動(dòng)元素)。
方案二:對(duì)象
優(yōu)點(diǎn):
- 通過 id 查找、更新、刪除極快(O(1))。
- 內(nèi)存稍?。o需重復(fù)存 id)。
- 天然保證 id 唯一性(鍵不能重復(fù))。
缺點(diǎn):
- 沒有順序保證(ES6 之后對(duì)象鍵按創(chuàng)建順序枚舉,但刪除再添加可能影響順序)。
- 遍歷需要先轉(zhuǎn)換(
Object.values),且轉(zhuǎn)換結(jié)果是一個(gè)新數(shù)組,頻繁遍歷可能產(chǎn)生臨時(shí)對(duì)象開銷。 - 不能直接使用數(shù)組方法(如
map,filter)。
6. 常見優(yōu)化實(shí)踐
在實(shí)際開發(fā)中,經(jīng)常需要兼顧快速查找和順序遍歷。這時(shí)可以采用復(fù)合結(jié)構(gòu):
const productsList = []; // 用于順序展示
const productsMap = {}; // 用于快速查找
// 添加產(chǎn)品
function addProduct(product) {
productsList.push(product);
productsMap[product.id] = product;
}
// 通過 id 查找
function getProduct(id) {
return productsMap[id];
}
// 刪除產(chǎn)品(假設(shè)不關(guān)心順序,用 filter 重建列表)
function deleteProduct(id) {
productsList = productsList.filter(p => p.id !== id);
delete productsMap[id];
}
這種方式結(jié)合了兩者的優(yōu)點(diǎn),但需要維護(hù)兩個(gè)結(jié)構(gòu)的一致性。
7. 如何選擇
如果你的應(yīng)用主要場景是:
- 根據(jù) id 頻繁查找、更新(如購物車、商品詳情頁) → 選對(duì)象
- 展示產(chǎn)品列表、排序、過濾(如后臺(tái)管理列表) → 選數(shù)組
- 兩者都很重要 → 考慮復(fù)合結(jié)構(gòu)
數(shù)據(jù)量大小:如果數(shù)據(jù)量很小(幾十條),兩種方案性能差異可以忽略,選你寫起來更方便的即可。
是否需要保持順序:如果需要按特定順序展示(如按添加時(shí)間),數(shù)組更合適;如果順序不重要,對(duì)象也能滿足。
8. 內(nèi)部機(jī)制延伸理解
數(shù)組查找為什么慢?因?yàn)閿?shù)組本身沒有建立 id 到索引的映射,每次查找都必須遍歷所有元素,直到找到匹配的 id。如果數(shù)組很大,這個(gè)開銷會(huì)線性增長。
對(duì)象鍵訪問為什么快?對(duì)象在內(nèi)存中通過哈希函數(shù)將鍵映射到存儲(chǔ)位置,平均只需一次計(jì)算就能定位到值,無論對(duì)象中有多少屬性(理想情況下)。
delete 操作的影響delete obj[key] 會(huì)在對(duì)象中留下一個(gè)“空洞”,如果對(duì)象之前處于快速模式,可能會(huì)觸發(fā)引擎將其降級(jí)為慢速字典模式,后續(xù)屬性訪問性能下降。因此,如果頻繁刪除并重新添加大量屬性,建議用 undefined 標(biāo)記或改用 Map(Map 專門為頻繁增刪設(shè)計(jì),性能更好)。
總結(jié)
兩種方案各有優(yōu)劣,沒有絕對(duì)的好壞。理解它們的底層行為后,你可以根據(jù)業(yè)務(wù)場景的讀寫比例、是否強(qiáng)調(diào)順序、數(shù)據(jù)量級(jí)來靈活選擇。在大多數(shù)中大型應(yīng)用中,對(duì)象(或 Map)用于快速查找,數(shù)組用于列表渲染是常見模式。
到此這篇關(guān)于一文詳解JavaScript中使用對(duì)象數(shù)組、對(duì)象(字典)保存數(shù)據(jù)的區(qū)別的文章就介紹到這了,更多相關(guān)JavaScript存儲(chǔ)數(shù)據(jù)方法對(duì)比內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
多種js圖片預(yù)加載實(shí)現(xiàn)方式分享
這篇文章主要為大家詳細(xì)介紹了多種js圖片預(yù)加載實(shí)現(xiàn)方式,包括html標(biāo)簽或css加載圖片、純js實(shí)現(xiàn)預(yù)加載,感興趣的小伙伴們可以參考一下2016-02-02
js實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù)瀑布流
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù)瀑布流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
請(qǐng)求時(shí)token過期自動(dòng)刷新token操作
這篇文章主要介紹了請(qǐng)求時(shí)token過期自動(dòng)刷新token操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Javascript highcharts 餅圖顯示數(shù)量和百分比實(shí)例代碼
這篇文章主要介紹了Javascript highcharts 餅圖顯示數(shù)量和百分比實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下2016-12-12
layui 實(shí)現(xiàn)table翻頁滾動(dòng)條位置保持不變的例子
今天小編就為大家分享一篇layui 實(shí)現(xiàn)table翻頁滾動(dòng)條位置保持不變的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
JavaScript實(shí)現(xiàn)圖片懶加載的兩種方式
現(xiàn)在的科技發(fā)達(dá),圖片的資源占比越來越大,對(duì)圖片在頁面的優(yōu)化已經(jīng)成為前端開發(fā)必備的技術(shù)之一,難的圖片懶加載方法咱們看著頭大,簡單,易懂的才適合我們程序員,所以本文給大家介紹了JavaScript實(shí)現(xiàn)圖片懶加載的兩種方式,需要的朋友可以參考下2024-04-04
移動(dòng)端web滾動(dòng)分頁的實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了移動(dòng)端web滾動(dòng)分頁的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05

