国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何利用JavaScript的Map提升性能

notebin / 3613人閱讀

摘要:測(cè)試結(jié)果展示了使用的性能收益,尤其是添加和刪除鍵值的時(shí)。這個(gè)結(jié)果著實(shí)令人震驚,但是沒有循環(huán),添加屬性的性能勝過常規(guī)對(duì)象。

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

在這篇文章中,我將剖析Map,它究竟有何不同,哪里可以派上用場(chǎng),相比于常規(guī)對(duì)象有什么性能優(yōu)勢(shì)。

Map與常規(guī)對(duì)象有什么不同

Map和常規(guī)對(duì)象主要有2個(gè)不同之處。

1.無限制的鍵(Key)

常規(guī)JavaScript對(duì)象的鍵必須是StringSymbol,下面的對(duì)象說明的這一點(diǎn):

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

const regularObject = {
  string1: "value1",
  [string2]: "value2",
  [symbol]: "value3"
};

相比之下,Map允許你使用函數(shù)、對(duì)象和其它簡(jiǎn)單的類型(包括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");

在鏈接不同數(shù)據(jù)類型時(shí),這個(gè)特性提供了極大的靈活性。

2.直接遍歷

在常規(guī)對(duì)象中,為了遍歷keys、values和entries,你必須將它們轉(zhuǎn)換為數(shù)組,如使用Object.keys()、Object.values()Object.entries(),或者使用for ... in循環(huán),因?yàn)槌R?guī)對(duì)象不能直接遍歷,另外for ... in循環(huán)還有一些限制:它僅僅遍歷可枚舉屬性、非Symbol屬性,并且遍歷的順序是任意的。

Map可以直接遍歷,并且由于它是鍵控集合,遍歷的順序和插入鍵值的順序是一致的。你可以使用for ... of循環(huán)或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);
});

還有一個(gè)好處就是,你可以調(diào)用map.size屬性來獲取鍵值數(shù)量,而對(duì)于常規(guī)對(duì)象,為了做到這樣你必須先轉(zhuǎn)換為數(shù)組,然后獲取數(shù)組長(zhǎng)度,如:Object.keys({}).length。

MapSet有何不同

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

最大的不同是Map通過鍵值(key/value)成對(duì)出現(xiàn),就像你可以把一個(gè)數(shù)組轉(zhuǎn)換為Set,你也可以把二維數(shù)組轉(zhuǎn)換為Map

const set = new Set([1, 2, 3, 4]);
const map = new Map([["one", 1], ["two", 2], ["three", 3], ["four", 4]]);
類型轉(zhuǎn)換

要將Map切換回?cái)?shù)組,你可以使用ES6的結(jié)構(gòu)語法:

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

到目前為止,將Map與常規(guī)對(duì)象的互相轉(zhuǎn)換依然不是很方便,所以你可能需要依賴一個(gè)函數(shù)方法,如下:

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

但是現(xiàn)在,在八月份ES2019的首次展示中,我們看見了Object引入了2個(gè)新方法:Object.entries()Object.fromEntries(),這可以使上述方法簡(jiǎn)化許多:

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

在你使用Object.fromEntries轉(zhuǎn)換map為object之前,確保map的key在轉(zhuǎn)換為字符串時(shí)會(huì)產(chǎn)生唯一的結(jié)果,否則你將面臨數(shù)據(jù)丟失的風(fēng)險(xiǎn)。

性能測(cè)試

為了準(zhǔn)備測(cè)試,我會(huì)創(chuàng)建一個(gè)對(duì)象和一個(gè)map,它們都有1000000個(gè)相同的鍵值。

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

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

查詢

let result;
console.time("Object");
result = obj.hasOwnProperty("999999");
console.timeEnd("Object");
// Object: 0.250ms

console.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.229ms

console.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.376ms

console.time("Map");
map.delete(n);
console.timeEnd("Map");
// Map: 0.012ms (31 times faster!)
Map在什么情況下更慢

在測(cè)試中,我發(fā)現(xiàn)一種情況常規(guī)對(duì)象的性能更好:使用for循環(huán)去創(chuàng)建常規(guī)對(duì)象和map。這個(gè)結(jié)果著實(shí)令人震驚,但是沒有for循環(huán),map添加屬性的性能勝過常規(guī)對(duì)象。

console.time("Object");
for (let i = 0; i < n; i++) {
  obj[i] = i;
}
console.timeEnd("Object");
// Object: 32.143ms

let 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)
舉個(gè)例子

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

console.log(isAnagram("anagram", "gramana")); // Should return true
console.log(isAnagram("anagram", "margnna")); // Should return false

有許多方法可以做到,但是這里,map可以幫忙我們創(chuàng)建一個(gè)最簡(jiǎn)單、最快速的解決方案:

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

在這個(gè)例子中,當(dāng)涉及到動(dòng)態(tài)添加和刪除鍵值,無法提前確認(rèn)數(shù)據(jù)結(jié)構(gòu)(或者說鍵值的數(shù)量)時(shí),map比object更合適。

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

譯者注:我個(gè)人不太同意作者的觀點(diǎn),從以上的描述來看,Map更像是以空間為代價(jià),換取速度上的提升。那么對(duì)于空間和速度的衡量,必然存在一個(gè)閾值。在數(shù)據(jù)量比較少時(shí),相比與速度的提升,其犧牲的空間代價(jià)更大,此時(shí)顯然是不適合使用Map;當(dāng)數(shù)據(jù)量足夠大時(shí),此時(shí)空間的代價(jià)影響更小。所以,看開發(fā)者如何衡量?jī)烧咧g的關(guān)系,選擇最優(yōu)解。

原文鏈接

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/106726.html

相關(guān)文章

  • 前端每周清單第 29 期:Web 現(xiàn)狀分析與優(yōu)化策略、Vue 單元測(cè)試、Headless Chrom

    摘要:前端每周清單第期現(xiàn)狀分析與優(yōu)化策略單元測(cè)試爬蟲作者王下邀月熊編輯徐川前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000011008022); 前端每周清單第 29 期:Web 現(xiàn)狀分析與優(yōu)化策略...

    HackerShell 評(píng)論0 收藏0
  • The Cost Of JavaScript 2018 精讀

    摘要:目前我們的業(yè)務(wù)項(xiàng)目采用的來進(jìn)行優(yōu)化和首屏性能提升。可變性需要讓開發(fā)人員降低開發(fā)時(shí)的基準(zhǔn)線,來保證每一個(gè)用戶的體驗(yàn)。對(duì)于路由的切分以及庫的引入來說,這一個(gè)原則至關(guān)重要??焖偕梢环菡军c(diǎn)的性能審查報(bào)告。 The Cost Of JavaScript 2018 關(guān)于原文 原文是在Medium上面看到的,Chrome工程師Addy Osmani發(fā)布的一篇文章,這位的Medium上面的自我介紹里...

    lushan 評(píng)論0 收藏0
  • 前端每周清單第 49 期:Webpack 4 Beta 嘗鮮,React Windowing 與 s

    摘要:盡管等待了多年,但是最終還是發(fā)布了正式版本與上一個(gè)版本相比未有重大變化,主要著眼于部分錯(cuò)誤修復(fù)與提升。能夠?qū)惒胶瘮?shù)移入獨(dú)立線程中,可以看做函數(shù)的單函數(shù)簡(jiǎn)化版。不過需要注意的是,僅支持純函數(shù),其會(huì)在獨(dú)立的作用域中運(yùn)行這些函數(shù)。 showImg(https://segmentfault.com/img/remote/1460000013038757); 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)...

    muzhuyu 評(píng)論0 收藏0
  • 前端面試題(4)JavaScript

    摘要:變量聲明提升在中,函數(shù)聲明與變量聲明經(jīng)常被引擎隱式地提升到當(dāng)前作用域的頂部。對(duì)象的方法和屬性是在全局范圍內(nèi)有效的。未形成標(biāo)準(zhǔn),實(shí)現(xiàn)混亂。 前端面試題JavaScript(一) JavaScript的組成 JavaScript 由以下三部分組成: ECMAScript(核心):JavaScript 語言基礎(chǔ) DOM(文檔對(duì)象模型):規(guī)定了訪問HTML和XML的接口 BOM(瀏覽器對(duì)...

    1treeS 評(píng)論0 收藏0
  • 前端面試題(4)JavaScript

    摘要:變量聲明提升在中,函數(shù)聲明與變量聲明經(jīng)常被引擎隱式地提升到當(dāng)前作用域的頂部。對(duì)象的方法和屬性是在全局范圍內(nèi)有效的。未形成標(biāo)準(zhǔn),實(shí)現(xiàn)混亂。 前端面試題JavaScript(一) JavaScript的組成 JavaScript 由以下三部分組成: ECMAScript(核心):JavaScript 語言基礎(chǔ) DOM(文檔對(duì)象模型):規(guī)定了訪問HTML和XML的接口 BOM(瀏覽器對(duì)...

    spademan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<