js map對象遍歷_何時使用 Map 來代替變通的 JS 對象

JS 普通對象 {key: 'value'} 用于存放結構化數據。但有一件事我覺得很煩:對象鍵必須是字符串(或很少使用的 symbol)。

如果將數字用作鍵會怎樣?在這種情況下不會有錯誤:

const?names?=?{
??1:?'One',
??2:?'Two',
};

Object.keys(names);?//?=>?['1',?'2']

JS 會隱式地將對象的鍵轉換為字符串,這種默認行為丟失了類型的一致性,要解決也挺棘手的。但 ES6 中的Map 對象可以幫我們解決這類的問題,Look See See。

1. Map 接受任何類型的鍵

如前所述,如果對象的鍵不是 stringsymbol,JS 將隱式地將其轉換為字符串。

幸運的是,map 的鍵類型沒有問題

const?numbersMap?=?new?Map();

numbersMap.set(1,?'one');
numbersMap.set(2,?'two');

[...numbersMap.keys()];?//?=>?[1,?2]

12numbersMap 中的鍵,這些鍵的類型(數字)保持不變。

可以在 mpa 中使用任何鍵類型:數字、布爾值、字符串和 symbol

const?booleansMap?=?new?Map();

booleansMap.set(true,?"Yep");
booleansMap.set(false,?"Nope");

[...booleansMap.keys()];?//?=>?[true,?false]

booleansMap 使用 booleans 作為鍵,沒有問題。相反,布爾鍵在普通對象中不起作用。

來突破一下想象:是否將整個對象作為 map 的鍵,答案:可以的。

1.1 對象作為鍵

假設你需要存儲一些與對象相關的數據,而不需要將這些數據附加到對象本身。使用普通對象是不可能的。

解決方法是使用對象-值元組數組:

const?foo?=?{?name:?'foo'?};
const?bar?=?{?name:?'bar'?};

const?kindOfMap?=?[
??[foo,?'Foo?related?data'],
??[bar,?'Bar?related?data']
]

kindOfMap 是一個數組,包含對象和關聯值的對。

這種方法最大的問題是按鍵訪問值的復雜度O(n),咱們必須遍歷整個數組才能通過鍵獲得所需的值。

function?getByKey(kindOfMap,?key)?{
??for?(const?[k,?v]?of?kindOfMap)?{
????if?(key?===?k)?{
??????return?v;
????}
??}
??return?undefined;
}

getByKey(kindOfMap,?foo);?//?=>?'Foo?related?data'

WeakMap (Map的一個專門版本)不需要這么麻煩就能做到上面的事情:它只接受對象作為鍵

MapWeakmap 之間的主要區別是,Weakmap 允許對鍵對象進行垃圾收集,從而防止內存泄漏。

好了,用 WeakMap 重構上面的代碼就變得很簡單了:

const?foo?=?{?name:?'foo'?};
const?bar?=?{?name:?'bar'?};

const?mapOfObjects?=?new?WeakMap();

mapOfObjects.set(foo,?'Foo?related?data');
mapOfObjects.set(bar,?'Bar?related?data');

mapOfObjects.get(foo);?//?=>?'Foo?related?data'

Map 相反,WeakMap 只接受對象作為鍵,并少了一些方法。

2. map 對鍵名沒有限制

JS 中的任何對象都從原型對象繼承屬性,普通對象也是如此。

如果重寫從原型繼承的屬性,則可能會破壞依賴這些原型屬性的代碼:

function?isPlainObject(value)?{
??return?value.toString()?===?'[object?Object]';
}

const?actor?=?{
??name:?'Harrison?Ford',
??toString:?'Actor:?Harrison?Ford'
};

//?Does?not?work!
isPlainObject(actor);?//?TypeError:?value.toString?is?not?a?function

在對象參與者上定義的屬性 toString 覆蓋從原型繼承的 toString() 方法。這中斷了isObject(),因為它依賴于 toString() 方法。

檢查普通對象從原型繼承的屬性和方法的列表, 避免使用這些方法名定義自定義屬性。

例如,假設有一個管理某些自定義字段的用戶界面。用戶可以通過指定名稱和值來添加自定義字段:

37e709ee99ec4321c2c58545982fc21f.png

將定制字段的狀態存儲到普通對象中會很方便:

const?userCustomFields?=?{
??'color':????'blue',
??'size':?????'medium',
??'toString':?'A?blue?box'
};

但是用戶可能會選擇一個自定義字段名稱,例如toString(如示例中所示),構造函數等,這可能會破壞咱們的對象。

不要使用用戶輸入的值作為普通對象上鍵。

map 沒有這個問題,鍵值名稱不受限制:

function?isMap(value)?{
??return?value.toString()?===?'[object?Map]';
}

const?actorMap?=?new?Map();

actorMap.set('name',?'Harrison?Ford');
actorMap.set('toString',?'Actor:?Harrison?Ford');

//?Works!
isMap(actorMap);?//?=>?true

不管 actorMap 有一個名為toString的屬性,toString()方法都可以正常工作。

3. map 是可迭代

為了遍歷普通對象的屬性,必須使用其他的輔助靜態函數,如 Object.keys()Object.entries():

const?colorsHex?=?{
??'white':?'#FFFFFF',
??'black':?'#000000'
};

for?(const?[color,?hex]?of?Object.entries(colorsHex))?{
??console.log(color,?hex);
}
//?'white'?'#FFFFFF'
//?'black'?'#000000'

Object.entries(colorsHex) 返回從對象提取的鍵值對數組。

但是,map 本身是可迭代的:

const?colorsHexMap?=?new?Map();

colorsHexMap.set('white',?'#FFFFFF');
colorsHexMap.set('black',?'#000000');

for?(const?[color,?hex]?of?colorsHexMap)?{
??console.log(color,?hex);
}
//?'white'?'#FFFFFF'
//?'black'?'#000000'

colorsHexMap是可迭代。可以在任何接受迭代的地方使用它:for()循環,展開運算符[...map]

map 提供了返回可迭代方法:map.keys() 遍歷鍵,map.values() 遍歷值

4. map 的大小

普通對象的另一個問題是,您無法立馬知道它包含的屬性的數量。

const?exams?=?{
??'John?Smith':?'10?points',
??'Jane?Doe':?'8?points',
};

Object.keys(exams).length;?//?=>?2

要確定 exams 的大小,必須通過所有鍵來確定它們的數量。

map 提供了 size 屬性,表示屬性的數量。

const?examsMap?=?new?Map([
??['John?Smith',?'10?points'],
??['Jane?Doe',?'8?points'],
]);

examsMap.size;?//?=>?2

確定 map 的屬性的數量更加簡單:examsMap.size

總結

普通 JS 對象通常可以很好地保存結構化數據,但它們也有一些局限性:

  1. 只能用字符串或 sybmol 作為鍵

  2. 自己的對象屬性可能會與從原型繼承的屬性鍵沖突(例如 toStringconstructor等)。

  3. 對象不能用作鍵

所有這些問題都可以通過 map 輕松解決。而且,它們提供了諸如迭代器和易于進行大小查找之類的好處。

不要將 map 當作普通對象的替代品,而應視為是普通對象補充。

你還知道 map 比普通物體的其他好處嗎?請在下方留言。


原文:https://dmitripavlutin.com/maps-vs-plain-objects-javascript/
作者:Dmitri Pavlutin ?譯者:前端小智 ?來源:dmitripavlutin

交流

337798e76d484b16a17da2e58c788186.png

Vue 中如何讓 input 聚焦?

高級 Vue 技巧:控制父類的 slot

如何構建運行良好的Vue組件

如何在 Vue 中對事件進行防抖和節流?(小智的第三個視頻)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532087.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532087.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532087.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql怎么顯示結果窗口_mysql8中窗口函數

在以前的MySQL版本中是沒有窗口函數的,直到MySQL8.0才引入了窗口函數。窗口函數是對查詢中的每一條記錄執行一個計算,并且這個計算結果是用與該條記錄相關的多條記錄得到的。1.窗口函數與聚合函數窗口函數與聚合函數很像,他們都是在一組記錄而…

python控制臺輸入字符串作為參數_Python-如何將字符串傳遞到subprocess.Popen(使用stdin參數)?...

小編典典Popen.communicate() 說明文件:請注意,如果要將數據發送到進程的stdin,則需要使用stdin PIPE創建Popen對象。同樣,要在結果元組中獲得除None以外的任何內容,你還需要提供stdout PIPE和/或stderr PIPE。替換…

log4jdbc mysql_[簡單]log4jdbc-log4j2配置簡記_MySQL

log4jdbc-log4j2,就不多說了,不了解的可以谷歌,附上log4jdbc-log4j2的官方鏈接:https://code.google.com/p/log4jdbc-log4j2/ ,上面有非常詳細的介紹。簡單的貼下配置文件,其他的見附件:databas…

vb實時錯誤6 溢出_java內存溢出系列(6): Out of swap space?

本文是java內存溢出系列第6小篇。JVM啟動參數指定了最大內存限制。如 -Xmx 以及相關的其他啟動參數. 假若JVM使用的內存總量超過可用的物理內存, 操作系統就會用到虛擬內存。錯誤信息 java.lang.OutOfMemoryError: Out of swap space? 表明, 交換空間(swap space,虛擬內存) 不…

java備份還原mysql數據庫_Java備份還原Mysql數據庫

///實體類package com.ews.util;/*** 系統備份展示對象** */public class DataFile {private String fileName;//備份文件的名稱private String fileDate;//備份文件的日期private String filePath;//備份文件的地址private String fileSize;//備份文件的大小public String get…

學pyqt5之前需要學python嗎_快速學習pyqt5(1)--入門

學習于:PyQt5圖形界面編程 想要系統學習的同學建議可以去這個專欄好好學習,沒有任何語言基礎和計算機基礎的也建議直接去看那個專欄。我這里是有java基礎了,所以就不重復,針對快速學習使用。學習這個的目的是完成學校的SIT項目&am…

reboot mysql fail_mysql 5.7.18,在系統重啟后,為什么無法啟動?

度娘也不給力,只好自己研究了。先把結論寫出來吧。把pid文件換個位置,就好了。問題是, mysqld.servce的文件是從mysql的安裝目錄拷貝的,導致沒有懷疑pid文件位置的問題。一開始還懷疑是不是自己在一些文件里拼寫有誤。后來&#x…

mysql 查看鎖_別吵吵,分布式鎖也是鎖

Tomcat是這個系統的核心組成部分, 每當有用戶請求過來,Tomcat就會從線程池里找個線程來處理,有的執行登錄,有的查看購物車,有的下訂單,看著屬下們盡心盡職地工作,完成人類的請求,Tom…

php解析js的 arraybuffer_JS的所謂的第七種數據類型Symbol

首先,為什么說叫所謂呢?因為在2007年之前Js給予我們typeof解析數據類型的一共有六種(一直有爭議,但是我們暫時就按typeof來算)functionNumberObjectbooleanStringundefined但當我們去 typeof Symbol () 的時候,會驚奇的發現&#…

JAVA MYSQL從數據庫中提取圖片_java web將圖片存到儲數據庫和從數據庫中讀取圖片...

(Notice:以下所有經驗也是我根據網上的經驗整理的,如有侵權可以聯系我刪除,Wx:IT_Ezra,QQ 654303408。 有問題討論也可聯系我,QQ同上。)一、分析一下基本流程從前臺頁面獲取圖片,后臺接收圖片文件轉化成數據…

Ubuntu系統如何安裝和卸載CUDA和CUDNN

背景 最近在學習PaddlePaddle在各個顯卡驅動版本的安裝和使用,所以同時也學習如何在Ubuntu安裝和卸載CUDA和CUDNN,在學習過程中,順便記錄學習過程。在供大家學習的同時,也在加強自己的記憶。本文章以卸載CUDA 8.0 和 CUDNN 7.05 …

session.merge 緩存不更新_如何保證緩存與數據庫雙寫時的數據一致性?

在做系統優化時,想到了將數據進行分級存儲的思路。因為在系統中會存在一些數據,有些數據的實時性要求不高,比如一些配置信息。基本上配置了很久才會變一次。而有一些數據實時性要求非常高,比如訂單和流水的數據。所以這里根據數據…

java替換圖片中文字_Java 添加、替換、刪除Word中的圖片

文檔中,可以通過圖文混排的方式來增加內容的可讀性,相比純文本文檔,在內容展現方式上也更具美觀性。在給文檔添加圖片時,可設置圖片的文本環繞方式、旋轉角度、圖片高度/寬度等;另外,也可對文檔中已有的圖片…

kafka如何保證不重復消費又不丟失數據_Kafka寫入的數據如何保證不丟失?

我們暫且不考慮寫磁盤的具體過程,先大致看看下面的圖,這代表了 Kafka 的核心架構原理。Kafka 分布式存儲架構那么現在問題來了,如果每天產生幾十 TB 的數據,難道都寫一臺機器的磁盤上嗎?這明顯是不靠譜的啊!所以說,這…

不允許輸入特殊字符的正則表達式_JavaScript正則表達式常用技巧

正則表達式是用于匹配字符串中字符組合的模式。在 JavaScript 中,正則表達式也是對象。這些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。正則表達式的掌握程度能粗略地看出程序員的技術底子&#xff…

latex 算法_GitHub項目awesome-latex-drawing新增內容(四):繪制貝葉斯網絡

近期,我們整理和開源了一個基于LaTeX的科技繪圖項目,并將其取名為awesome-latex-drawing(GitHub網址為:https://github.com/xinychen/awesome-latex-drawing),案例包括貝葉斯網絡、圖模型、矩陣/張量示意圖…

python123動物重量排序_python進階

面向對象oopclass Student(object):def __init__(self,name,score)self.name nameself.score scoredef print_score(self)print(%s: %s % (self.name,self.score))給對象發消息實際上就是調用對象對應的關聯函數,我們稱之為對象的方法(Method)。面向對象的程序寫出…

mysql中的生日應該是什么類型_MySQL中的定點數類型

上一篇文章我們嘮叨了浮點數,知道了浮點數存儲小數是不精確的。本篇繼續嘮叨一下MySQL中的另一種存儲小數的方式 —— 定點數。浮點數文章閃現:什么, 0.3 - 0.2 ≠ 0.1 ? 什么鬼定點數類型正因為用浮點數表示小數可能會有不精確的情況,在一些…

python怎么制作圖像_python數字圖像處理(5):圖像的繪制

實際上前面我們就已經用到了圖像的繪制,如:io.imshow(img)這一行代碼的實質是利用matplotlib包對圖片進行繪制,繪制成功后,返回一個matplotlib類型的數據。因此,我們也可以這樣寫:importmatplotlib.pyplot …

axios代理跨域 cli4_vuecli 3.0之跨域請求代理配置及axios路徑配置 莫小龍

vue-cli 3.0之跨域請求代理配置及axios路徑配置問題:在前后端分離的跨域請求中,報跨域問題配置:vue.config.js:module.exports {runtimeCompiler: true,publicPath: /, // 設置打包文件相對路徑devServer: {// open: process.pla…