JavaScript 中有了Object 為什么還需要 Map 呢
一、別把對(duì)象當(dāng) Map
1、可能通過(guò)原型鏈訪問(wèn)到未定義的屬性
假設(shè)現(xiàn)有場(chǎng)景,開(kāi)發(fā)一個(gè)網(wǎng)站,需要提供日語(yǔ)、漢語(yǔ)、韓語(yǔ)三種語(yǔ)言,我們可以定義一個(gè)字典去管理。
const dictionary = {
'ja': {
'Ninjas for hire': '忍者を雇う',
},
'zh': {
'Ninjas for hire': '忍者出租',
},
'ko': {
'Ninjas for hire': '고용 닌자',
}
}
console.log(dictionary.ja['Ninjas for hire']) // 忍者を雇う
console.log(dictionary.zh['Ninjas for hire']) // 忍者出租
console.log(dictionary.ko['Ninjas for hire']) // 고용 닌자
這樣我們就把不同語(yǔ)言的字典管理起來(lái)了。但是,當(dāng)我們?cè)噲D訪問(wèn) constroctor 屬性,問(wèn)題就出現(xiàn)了。
console.log(dictionary.ko['constructor']) // ƒ Object() { [native code] }
對(duì)于不存在的屬性,我們期望得到 undefined,結(jié)果卻通過(guò)原型鏈訪問(wèn)到了未定義的屬性,原型對(duì)象的 constructor 屬性,指向構(gòu)造函數(shù)。
此處有一個(gè)解決辦法是把原型設(shè)置為 null
Object.setPrototypeOf(dictionary.ko, null) console.log(dictionary.ko['constructor']) // undefined
2、對(duì)象的 Key 只能是字符串
假設(shè)需要將對(duì)象的 key 映射為 html 節(jié)點(diǎn)。我們寫(xiě)如下代碼:
/* html部分
<div id="firstElement"></div>
<div id="secondElement"></div>
*/
const firstElement = document.getElementById('firstElement')
const secondElement = document.getElementById('secondElement')
const map = {}
map[firstElement] = {
data: 'firstElement'
}
map[secondElement] = {
data: 'secondElement'
}
console.log(map[firstElement].data) // secondElement
console.log(map[secondElement].data) // secondElement
第一個(gè)元素的數(shù)據(jù)被覆蓋了,原因是對(duì)象中的 key 只能是字符串類型,當(dāng)我們沒(méi)有使用字符串類型時(shí),它會(huì)隱式調(diào)用 toString() 函數(shù)進(jìn)行轉(zhuǎn)換。于是兩個(gè) html 元素都被轉(zhuǎn)為字符串 [object HTMLDivElement] 。
對(duì)象的鍵也可以為 Symbol,不過(guò)在 for..in 遍歷和 Object.keys() 以及用 JSON.stringify() 進(jìn)行序列化的時(shí)候,都會(huì)忽略為 Symbol 的鍵。
二、使用 Map
1、Map 常用操作
Map 可以使用任何 JavaScript 數(shù)據(jù)類型作為鍵
function People(name) {
this.name = name
}
const zhangsan = new People('zhangsan')
const xiaoming = new People('xiaoming')
const lihua = new People('lihua')
// 創(chuàng)建 Map
const map = new Map()
// 創(chuàng)建 Map 并進(jìn)行初始化 將二維鍵值對(duì)數(shù)組轉(zhuǎn)換成一個(gè)Map對(duì)象
const map1 = new Map([
['key1', 'val1'],
['key2', 'val2'],
])
// 將 Map 轉(zhuǎn)為二維數(shù)組
console.log(Array.from(map1)) // [ [ 'key1', 'val1' ], [ 'key2', 'val2' ] ]
// 設(shè)置鍵值映射關(guān)系
map.set(zhangsan, { region: 'HB' })
map.set(xiaoming, { region: 'HN' })
// 根據(jù) key 獲取對(duì)應(yīng)值
console.log(map.get(zhangsan)) // { region: 'HB' }
console.log(map.get(xiaoming)) // { region: 'HN' }
// 獲取不存在的 key 得到 undefined
console.log(map.get(lihua)) // undefined
// 通過(guò) has 函數(shù)判斷指定 key 是否存在
console.log(map.has(lihua)) // false
console.log(map.has(xiaoming)) // true
// map存儲(chǔ)映射個(gè)數(shù)
console.log(map.size) // 2
// delete 刪除 key
map.delete(xiaoming)
console.log(map.has(xiaoming)) // false
console.log(map.size) // 1
// clear 清空 map
map.clear()
console.log(map.size) // 0
2、遍歷 Map
Map 可以確保遍歷的順序和插入的順序一致
const zhangsan = { name: 'zhangsan' }
const xiaoming = { name: 'xiaoming' }
const map = new Map()
map.set(zhangsan, { region: 'HB' })
map.set(xiaoming, { region: 'HN' })
// 每個(gè)鍵值對(duì)返回的是 [key, value] 的數(shù)組
for (let item of map) { // = for (let item of map.entries()) {
console.log(item)
// [ { name: 'zhangsan' }, { region: 'HB' } ]
// [ { name: 'xiaoming' }, { region: 'HN' } ]
}
// 遍歷 key
for (let key of map.keys()) {
console.log(key)
// { name: 'zhangsan' }
// { name: 'xiaoming' }
}
// 遍歷 value
for (let key of map.values()) {
console.log(key)
// { region: 'HB' }
// { region: 'HN' }
}
// 使用 forEach() 方法迭代 Map
map.forEach(function(value, key) {
console.log(key, value)
// { name: 'zhangsan' } { region: 'HB' }
// { name: 'xiaoming' } { region: 'HN' }
})
3、Map 中判斷 key 相等
Map 內(nèi)部使用 SameValueZero 比較操作。
關(guān)于SameValue 和 SameValueZero
SameValue (Object.is()) 和嚴(yán)格相等(===)相比,對(duì)于 NaN 和 +0,-0 的處理不同
Object.is(NaN, NaN) // true Object.is(0, -0) // false
SameValueZero 與 SameValue 的區(qū)別主要在于 0 與 -0 是否相等。
map.set(NaN, 0) map.set(0, 0) console.log(map.has(NaN)) // true console.log(map.has(-0)) // true
4、復(fù)制或合并 Map
Map 能像數(shù)組一樣被復(fù)制
let original = new Map([
[1, {}]
])
let clone = new Map(original) // 克隆 Map
console.log(clone.get(1)); // {}
console.log(original === clone) // false
console.log(original.get(1) === clone.get(1)) // true
多個(gè) Map 合并
let first = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let second = new Map([
[1, 'uno'],
[2, 'dos']
]);
// 合并兩個(gè) Map 對(duì)象時(shí),如果有重復(fù)的鍵值,則后面的會(huì)覆蓋前面的。
// 展開(kāi)運(yùn)算符本質(zhì)上是將 Map 對(duì)象轉(zhuǎn)換成數(shù)組。
let merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
5、Map 序列化
Map 無(wú)法被序列化,如果試圖用 JSON.stringify 獲得 Map 的 JSON 的話,只會(huì)得到 "{}"。
由于 Map 的鍵可以是任意數(shù)據(jù)類型,而 JSON 僅允許將字符串作為鍵,所以一般情況下無(wú)法將 Map 轉(zhuǎn)為 JSON。
不過(guò)可以通過(guò)下面的方式去嘗試序列化一個(gè) Map:
// 初始化 Map(1) {"key1" => "val1"}
const originMap = new Map([['key1', 'val1']])
// 序列化 "[[\"key1\",\"val1\"]]"
const mapStr = JSON.stringify(Array.from(originMap.entries()))
// 反序列化 Map(1) {"key1" => "val1"}
const cloneMap = new Map(JSON.parse(mapStr))
三、Map 和 Object 的性能差異
內(nèi)存占用
不同瀏覽器的情況不同,但給定固定大小的內(nèi)存,Map 大約可以比 Object 多存儲(chǔ) 50% 的鍵/值對(duì)。
插入性能
Map 略快,如果涉及大量操作,建議使用 Map。
查找速度
性能差異極小,但如果只包含少量鍵/值對(duì),則 Object 有時(shí)候速度更快。Object 作為數(shù)組使用時(shí)瀏覽器會(huì)進(jìn)行優(yōu)化。如果涉及大量查找操作,選擇 Object 會(huì)更好一些。
刪除性能
如果代碼涉及大量的刪除操作,建議選擇 Map。
到此這篇關(guān)于JavaScript 中有了Object 為什么還需要 Map 呢的文章就介紹到這了,更多相關(guān)JavaScript Map 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript中利用Array和Object實(shí)現(xiàn)Map的方法
- Springboot通過(guò)ObjectMapper配置json序列化詳解
- 使用ObjectMapper把Json轉(zhuǎn)換為復(fù)雜的實(shí)體類
- JavaScript中Object、map、weakmap的區(qū)別分析
- JavaScript?Map?和?Object?的區(qū)別解析
- JavaScript中Map與Object應(yīng)用場(chǎng)景
- JS中Map、WeakMap和Object的區(qū)別解析
- Javascript中Object和Map之間的轉(zhuǎn)換方法
- 面試???js中 Map和 Object 的區(qū)別小結(jié)
相關(guān)文章
詳解lodash中的cloneDeep使用細(xì)節(jié)
這篇文章主要為大家介紹了詳解lodash中的cloneDeep使用細(xì)節(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
使用compose函數(shù)優(yōu)化代碼提高可讀性及擴(kuò)展性
這篇文章主要為大家介紹了使用compose函數(shù)提高代碼可讀性及擴(kuò)展性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
document 和 document.all 分別什么時(shí)候用
document 和 document.all 分別什么時(shí)候用...2006-06-06
TypeScript對(duì)象解構(gòu)操作符在Spartacus實(shí)際項(xiàng)目開(kāi)發(fā)中的應(yīng)用解析
這篇文章主要為大家介紹了TypeScript對(duì)象解構(gòu)操作符在Spartacus實(shí)際項(xiàng)目開(kāi)發(fā)中的應(yīng)用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
微信小程序page的生命周期和音頻播放及監(jiān)聽(tīng)實(shí)例詳解
這篇文章主要介紹了微信小程序page的生命周期和音頻播放及監(jiān)聽(tīng)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04

