ES6之Map對象

Map 對象保存鍵值對,並且能夠記住鍵的原始插入順序任何值(對象或者原始值) 都可以作爲一個鍵或一個值

一個Map對象在迭代時會根據對象中元素的插入順序來進行 — 一個  for...of 循環在每次迭代後會返回一個形式爲[key,value]的數組。

  • 鍵的比較是基於 sameValueZero 算法:
  • NaN 是與 NaN 相等的(雖然 NaN !== NaN),剩下所有其它的值是根據 === 運算符的結果判斷是否相等。
  • 在目前的ECMAScript規範中,-0+0被認爲是相等的,儘管這在早期的草案中並不是這樣。有關詳細信息,請參閱瀏覽器兼容性 表中的“Value equality for -0 and 0”。

Map與普通對象的區別

  Map Object
意外的鍵

Map 默認情況不包含任何鍵。只包含顯式插入的鍵。

const func = () => null;
const object = {};
const array = [];
const bool = false;
const map = new Map();

map.set(func, 'value1');
map.set(object, 'value2');
map.set(array, 'value3');
map.set(bool, 'value4');
map.set(NaN, 'value5')

一個 Object 有一個原型, 原型鏈上的鍵名有可能和你自己在對象上的設置的鍵名產生衝突。

注意: 雖然 ES5 開始可以用 Object.create(null) 來創建一個沒有原型的對象,但是這種用法不太常見。

const symbol = Symbol();
const string2 = 'string2';

const regularObject = {
  'string1': 'value1',
  [string2]: 'value2',
  [symbol]: 'value3'
};
鍵的類型 一個 Map的鍵可以是任意值,包括函數、對象或任意基本類型。 一個Object 的鍵必須是一個 String 或是Symbol
鍵的順序

Map 中的 key 是有序的。因此,當迭代的時候,一個 Map 對象以插入的順序返回鍵值。

一個 Object 的鍵是無序的

注意:自ECMAScript 2015規範以來,對象確實保留了字符串和Symbol鍵的創建順序; 因此,在只有字符串鍵的對象上進行迭代將按插入順序產生鍵。

Size

 Map 的鍵值對個數可以輕易地通過size 屬性獲取

const map = new Map(); 
map.size屬性直接獲取長度

Object 的鍵值對個數只能手動計算

先轉換爲數組,然後獲取數組長度,
如:
Object.keys({}).length

迭代

Map  iterable 的,所以可以直接被迭代。

for (let [key, value] of map) {
  console.log(key);
  console.log(value);
};
map.forEach((key, value) => {
  console.log(key);
  console.log(value);
});

迭代一個Object需要以某種方式獲取它的鍵然後才能迭代。

必須將它們轉換爲數組,如使用Object.keys()Object.values()Object.entries(),或者使用for ... in循環,因爲常規對象不能直接遍歷,另外for ... in循環還有一些限制:它僅僅遍歷可枚舉屬性、非Symbol屬性,並且遍歷的順序是任意的

性能

在頻繁增刪鍵值對的場景下表現更好。

在頻繁添加和刪除鍵值對的場景下未作出優化。

let myMap = new Map();
myMap.set(NaN, "not a number");

myMap.get(NaN); // "not a number"

let otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"   雖然NaN!==NaN

遍歷:

let myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (let [key, value] of myMap) {
  console.log(key + " = " + value);
}
// 將會顯示兩個log。一個是"0 = zero"另一個是"1 = one"

for (let key of myMap.keys()) {
  console.log(key);
}
// 將會顯示兩個log。 一個是 "0" 另一個是 "1"

for (let value of myMap.values()) {
  console.log(value);
}
// 將會顯示兩個log。 一個是 "zero" 另一個是 "one"

for (let [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}
// 將會顯示兩個log。 一個是 "0 = zero" 另一個是 "1 = one"

MapSet有何不同

Map的行爲和Set非常相似,並且它們都包含一些相同的方法,包括:has、get、set、delete。它們兩者都是鍵控集合,就是說你可以使用像forEach的方法來遍歷元素,順序是按照插入鍵值排列的。

最大的不同是Map通過鍵值(key/value)成對出現,就像你可以把一個數組轉換爲Set,你也可以把二維數組轉換爲Map

const set = new Set([1, 2, 3, 4]);
const map = new Map([['one', 1], ['two', 2], ['three', 3], ['four', 4]]);

類型轉換:

 要將Map切換回數組,你可以使用ES6的解構語法:

const map = new Map([['one', 1], ['two', 2]]);
const arr = [...map];

 map對象和常規對象互換:

const mapToObj = map => {
  const obj = {};
  map.forEach((key, value) => { obj[key] = value });
  return obj;
};
const objToMap = obj => {
  const map = new Map();
  Object.keys(obj).forEach(key => { map.set(key, obj[key]) });
  return map;
};

ES2019的首次展示中,我們看見了Object引入了2個新方法:Object.entries()Object.fromEntries(),這可以使上述方法簡化許多:

const obj2 = Object.fromEntries(map);
const map2 = new Map(Object.entries(obj));

 

其他:

請注意!爲Map設置對象屬性也是可以的,但是可能引起大量的混亂。

所以,你還是可以這樣做...

let wrongMap = new Map()
wrongMap['bla'] = 'blaa'
wrongMap['bla2'] = 'blaaa2'

console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }

...但是,這樣做的話,它的行爲會不符合預期:

wrongMap.has('bla')    // false
wrongMap.delete('bla') // false
console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }

無論如何,和正確用法比較起來,幾乎沒有什麼不同: 

let myMap = new Map()
myMap.set('bla','blaa')
myMap.set('bla2','blaa2')
console.log(myMap)  // Map { 'bla' => 'blaa', 'bla2' => 'blaa2' }

myMap.has('bla')    // true
myMap.delete('bla') // true
console.log(myMap)  // Map { 'bla2' => 'blaa2' }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章