国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

利用JavaScript的Map提升性能的方法詳解

2024-05-06 16:54:10
字體:
來源:轉載
供稿:網友

前言

在ES6中引入JavaScript的新特性中,我們看到了Set和Map的介紹。與常規對象和Array不同的是,它們是“鍵控集合(keyed collections)”。這就是說它們的行為有稍許不同,并且在特定的上下文中使用,它們可以提供相當大的性能優勢。

在這篇文章中,我將剖析Map,它究竟有何不同,哪里可以派上用場,相比于常規對象有什么性能優勢。

Map與常規對象有什么不同

Map和常規對象主要有2個不同之處。

1.無限制的鍵(Key)

常規JavaScript對象的鍵必須是String或Symbol,下面的對象說明的這一點:

const symbol = Symbol();const string2 = 'string2';const regularObject = { string1: 'value1', [string2]: 'value2', [symbol]: 'value3'};

相比之下,Map允許你使用函數、對象和其它簡單的類型(包括NaN)作為鍵,如下代碼:

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');

在鏈接不同數據類型時,這個特性提供了極大的靈活性。

2.直接遍歷

在常規對象中,為了遍歷keys、values和entries,你必須將它們轉換為數組,如使用Object.keys()、Object.values()和Object.entries(),或者使用for ... in循環,因為常規對象不能直接遍歷,另外for ... in循環還有一些限制:它僅僅遍歷可枚舉屬性、非Symbol屬性,并且遍歷的順序是任意的。
而Map可以直接遍歷,并且由于它是鍵控集合,遍歷的順序和插入鍵值的順序是一致的。你可以使用for ... of循環或forEach方法來遍歷Map的entries,如下代碼:

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

還有一個好處就是,你可以調用map.size屬性來獲取鍵值數量,而對于常規對象,為了做到這樣你必須先轉換為數組,然后獲取數組長度,如:Object.keys({}).length。

Map和Set有何不同

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));

在你使用Object.fromEntries轉換map為object之前,確保map的key在轉換為字符串時會產生唯一的結果,否則你將面臨數據丟失的風險。

性能測試

為了準備測試,我會創建一個對象和一個map,它們都有1000000個相同的鍵值。

let obj = {}, map = new Map(), n = 1000000;for (let i = 0; i < n; i++) { obj[i] = i; map.set(i, i);}

然后我使用console.time()來衡量測試,由于我特定的系統和Node.js版本的原因,時間精度可能會有波動。測試結果展示了使用Map的性能收益,尤其是添加和刪除鍵值的時。

查詢

let result;console.time('Object');result = obj.hasOwnProperty('999999');console.timeEnd('Object');// Object: 0.250msconsole.time('Map');result = map.has(999999);console.timeEnd('Map');// Map: 0.095ms (2.6 times faster)

添加

console.time('Object');obj[n] = n;console.timeEnd('Object');// Object: 0.229msconsole.time('Map');map.set(n, n);console.timeEnd('Map');// Map: 0.005ms (45.8 times faster!)

刪除

console.time('Object');delete obj[n];console.timeEnd('Object');// Object: 0.376msconsole.time('Map');map.delete(n);console.timeEnd('Map');// Map: 0.012ms (31 times faster!)

Map在什么情況下更慢

在測試中,我發現一種情況常規對象的性能更好:使用for循環去創建常規對象和map。這個結果著實令人震驚,但是沒有for循環,map添加屬性的性能勝過常規對象。

console.time('Object');for (let i = 0; i < n; i++) { obj[i] = i;}console.timeEnd('Object');// Object: 32.143mslet obj = {}, map = new Map(), n = 1000000;console.time('Map');for (let i = 0; i < n; i++) { map.set(i, i);}console.timeEnd('Map');// Map: 163.828ms (5 times slower)

舉個例子

最后,讓我們看一個Map比常規對象更合適的例子,比如說我們想寫一個函數去檢查2個字符串是否由相同的字符串隨機排序。

console.log(isAnagram('anagram', 'gramana')); // Should return trueconsole.log(isAnagram('anagram', 'margnna')); // Should return false

有許多方法可以做到,但是這里,map可以幫忙我們創建一個最簡單、最快速的解決方案:

const isAnagram = (str1, str2) => { if (str1.length !== str2.length) {  return false; } const map = new Map(); for (let char of str1) {  const count = map.has(char) ? map.get(char) + 1 : 1;  map.set(char, count); } for (let char of str2) {  if (!map.has(char)) {   return false;  }  const count = map.get(char) - 1;  if (count === 0) {   map.delete(char);   continue;  }  map.set(char, count); } return map.size === 0;};

在這個例子中,當涉及到動態添加和刪除鍵值,無法提前確認數據結構(或者說鍵值的數量)時,map比object更合適。

我希望這篇文章對你有所幫助,如果你之前沒有使用過Map,不妨開闊你的眼界,衡量現代JavaScript的價值體現。

譯者注:我個人不太同意作者的觀點,從以上的描述來看,Map更像是以空間為代價,換取速度上的提升。那么對于空間和速度的衡量,必然存在一個閾值。在數據量比較少時,相比與速度的提升,其犧牲的空間代價更大,此時顯然是不適合使用Map;當數據量足夠大時,此時空間的代價影響更小。所以,看開發者如何衡量兩者之間的關系,選擇最優解。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 海门市| 璧山县| 曲麻莱县| 探索| 昭通市| 平泉县| 隆德县| 台中县| 从江县| 营口市| 梁河县| 怀仁县| 泉州市| 安阳市| 东莞市| 许昌市| 社旗县| 益阳市| 高雄县| 都昌县| 大洼县| 潞西市| 古交市| 汽车| 股票| 禹城市| 太保市| 平山县| 福海县| 扬中市| 聊城市| 颍上县| 新郑市| 寻甸| 嘉峪关市| 和政县| 鄂伦春自治旗| 景东| 阿城市| 汨罗市| 临沧市|