Map Object本質上是鍵值對的集合(Hash結構),但Object只能將字元串當做鍵,這就給Object帶來了很大的限制。 let data = {} let s = { name : '東方不敗' } data[s] = '西方求敗' // 如果鍵傳入非字元串的值,會自動為字元串 conso ...
Map
Object
本質上是鍵值對的集合(Hash結構),但Object
只能將字元串當做鍵,這就給Object
帶來了很大的限制。
let data = {}
let s = {
name : '東方不敗'
}
data[s] = '西方求敗'
// 如果鍵傳入非字元串的值,會自動為字元串
console.log(data); // {[object Object]: '西方求敗'}
console.log(data['[object Object]']); // 西方求敗
為瞭解決這個問題,es6
提供了Map
數據結構。它類似於對象,也是鍵值對集合,但鍵不局限於字元串
,各種類型的值都可以當做鍵。
- Object結構:
字元串鍵:值
- Map結構:
值鍵:值
let data2 = new Map()
let s2 = {
name : "藝術概論"
}
data2.set(s2,'中國工藝美術史')
console.log(data2.get(s2)); // 中國工藝美術史
console.log(data2); // key: {name: '藝術概論'} , value : "中國工藝美術史"
上面案例使用Map
的set
方法,將s2
當做data2
的鍵,使用get
方法取值。
Map的一些常用方法
方法 | 說明 |
---|---|
set() | 為Map對象添加一個指定鍵(key)和值(value)的新元素 |
get() | 用來獲取Map對象中指定的元素 |
has() | 返回boolean值,用來表明Map中是否存在該元素 |
delete() | 刪除對應元素 |
size | 返回Map的成員數 |
clear() | 清除Map所有成員,沒有返回值 |
let data2 = new Map()
let s2 = {
name : "藝術概論"
}
data2.set(s2,'中國工藝美術史')
data2.size; // 1
data2.has(s2); // treu
data2.delete(s2); // true
data2.has(s2); // false
data2.clear(); // undefined
Map參數
Map
可以接收數組作為參數,數組的成員是單個單個
的鍵值對的數組
let map = new Map([
['name','東方不敗'],
['title','西方求敗']
])
console.log(map.size); // 2
console.log(map); // {"name" => "東方不敗"}, {"title" => "西方求敗"}
console.log(map.has('name')); // true
console.log(map.get('name')); // 東方不敗
註意:如果有多個相同的鍵,後面的鍵值會覆蓋前面的鍵值
不僅是數組,任何具有Iterator
介面、且每個成員都是一個雙元素的數組
的數據結構,都可以當做Map
構造函數的參數,Set
和Map
也可以用來生成新的Map
Set作為參數
let set = new Set([['a',1],['b',2]])
let m = new Map(set)
console.log(m); // {'a' => 1, 'b' => 2}
console.log(m.get('a')); // 1
Map作為參數
let map2 = new Map([['text','世界現代設計史'],['name','王受之']])
let m2 = new Map(map2)
console.log(m2); // {'text' => '世界現代設計史', 'name' => '王受之'}
console.log(m2.get('text')); // 世界現代設計史
console.log(m2.get('hello')); // 讀取不存在的鍵會返回undefined
Map
只有對同一個對象的引用才視為同一個鍵
let map3 = new Map()
map3.set(['a',100])
console.log(map3.get(['a'])); // undefined
因為數組不是引用類型,生成多個數組,它們的記憶體地址是不一樣的,其實就是基礎數據類型和引用數據類型的應用,這裡的兩個['a']
看似是一樣的,其實它們根本就是兩個不同的值,Map
只有對同一個對象的引用才視為同一個鍵,沒有讀取到所以返回undefined
。請看下麵的例子
let map4 = new Map()
let b = ['b']
let b2 = ['b']
map4.set(b)
console.log(map4.get(b2)); // undefined
Map
的值其實是跟記憶體地址綁定的,記憶體地址不同,那麼鍵就不同(即使名字一模一樣),在這裡Map
就解決了同名屬性衝突的問題,當我們使用別人的庫時,使用對象名當做鍵,就不同擔心自己的屬性與別人的屬性相同了。
如果Map
的鍵是一個簡單數據類型的值,如:number、string、boolean
,只要這兩個值嚴格相等,Map
就視為同一個鍵,例如:0
和-0
就是同一個鍵,而布爾值true
和字元串true
就是不同的鍵,此外null
和undefined
也是不同的鍵。NaN
視為同一個鍵。
let n = new Map()
n.set(0,100)
console.log(n.get(-0)); // 100
n.set(5,123)
console.log(n.get('5')); // undefined
n.set(true,100)
console.log(n.get(1)); // undefined
n.set(NaN,123)
console.log(n.get(NaN)); // 123
n.set(null,100)
console.log(n.get(null)); // 100
console.log(n.get(undefined)); // undefined
Map遍歷方法
Map
提供三個遍歷器生成函數和一個遍歷方法
方法 | 說明 |
---|---|
Map.prototype.keys() | 返回鍵名的遍歷器。 |
Map.prototype.values() | 返回鍵值的遍歷器。 |
Map.prototype.entries() | 返回所有成員的遍歷器。 |
Map.prototype.forEach() | 遍歷 Map 的所有成員。 |
定義數據
let m3 = new Map([
['a',100],
['b',200],
['c',300]
])
keys
/* keys */
for(let k of m3.keys()){
console.log(k); // a b c
}
values
/* values */
for(let k of m3.values()){
console.log(k); // 100 200 300
}
entries
for(let k of m3.entries()){
console.log(k); // ['a', 100] ['b', 200] ['c', 300]
console.log(k[0],k[1]); // a 100 b 200 c 300
}
// 或
for(let [k,v] of m3.entries()){
console.log(k,v); // a 100 b 200 c 300
}
forEach
m3.forEach(el => console.log(el)) // 100 200 300
m3.forEach((val,index) => console.log(val,index)) // 100 'a' 200 'b' 300 'c'
Map數據結構轉換
Map轉數組
使用擴展運算符將Map
結構轉換為數組
let a = new Map([
['a',1],
['b',2],
['c',3]
])
console.log([...a.keys()]); // ['a','b','c']
console.log([...a.values()]); // [1,2,3]
console.log([...a.entries()]); // ['a', 1] ['b', 2] ['c', 3]
console.log([...a]); // ['a', 1] ['b', 2] ['c', 3]
轉換後的數組是一個真正的數組,可以使用數組方法
let back = [...a].filter((val,index) => val[1] == 2 )
console.log(back); // ['b',2]
數組轉Map
let a2 = new Map([
['name','東方不敗'],
[{num : 3},['abc']]
])
console.log(a2); // 0: {"name" => "東方不敗"} 1: {Object => Array(1)}
Map轉對象
let a3 = new Map()
.set('a',100)
.set('b',200)
/* 通過函數傳入map */
function mapToObj(mapVal){
// 在內部創建一個空對象
let obj = {}
// 遍歷map結構,給空對象賦值
for([k,v] of mapVal){
obj[k] = v
}
return obj
}
let mObj = mapToObj(a3)
console.log(mObj); // {a: 100, b: 200}
如果有非字元串鍵名,會被轉換成字元串再創建對象鍵名
對象轉Map
let obj = {'a':123,'b':456}
let mObj2 = new Map(Object.entries(obj))
console.log(mObj2); // {'a' => 123, 'b' => 456}
Map轉JSON
Map轉JSON需要區分兩種情況
1、Map鍵名都是字元串
2、Map鍵名有非字元串的情況
1、Map鍵名都是字元串
可以寫一個通用函數,用來將Map轉為JSON
let j = new Map()
.set('name','東方')
.set('text','不敗')
// mapToObj為上面創建的Map轉對象的函數
let shiftStrJson = (mapVal) => JSON.stringify(mapToObj(mapVal))
console.log(shiftStrJson(j)); // '{"name":"東方","text":"不敗"}'
2、Map鍵名有非字元串的情況
function shiftMaptoArrayJson(mapVal){
return JSON.stringify([...mapVal])
}
let j2 = new Map()
.set('name','東方')
.set('text','不敗')
let shiftStrJson2 = shiftMaptoArrayJson(j2)
console.log(shiftStrJson2); // '[["name","東方"],["text","不敗"]]'
以上兩種的轉換結果:
JSON轉Map
JSON轉Map需要區分兩種情況
1、Map鍵名都是字元串
2、Map鍵名有非字元串的情況
1、鍵名都是字元串
let strObj = '{"name":"東方","text":"不敗"}'
let strMap = new Map(Object.entries(JSON.parse(strObj)))
console.log(strMap); // {'name' => '東方', 'text' => '不敗'}
2、鍵名有非字元串情況
let strObj2 = '[["name","東方"],["text","不敗"]]'
let strMap2 = new Map(JSON.parse(strObj2))
console.log(strMap2); // {'name' => '東方', 'text' => '不敗'}
案例源碼:https://gitee.com/wang_fan_w/es6-science-institute
如果覺得這篇文章對你有幫助,歡迎點亮一下star喲