一文搞懂Map與Set的用法和區別解析

前言

作為前端開發人員,我們最常用的一些數據結構就是 ObjectArray 之類的,畢竟它們使用起來非常的方便。往往有些剛入門的同學都會忽視 SetMap 這兩種數據結構的存在,因為能用 setmap 實現的,基本上也可以使用對象或數組實現,而且還更簡單。

但是,存在必然合理,當你真正瞭解 MapSet 之後,你就會發現它們原來時如此美好!

1.基本概念

我們先來瞭解以下 MapSet 的基本概念,這樣才能幫助我們更好的使用。雖然我們通常把這兩種數據結構混合著來講,但事實上它們它們還是有挺大區別的!

1.1 Map(字典)

想要迅速瞭解一個新的數據結構或 API 是,查看官網是一個不錯的選擇。Map 在官網上也有解釋,我們一起來看下。

官網解釋:

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

官網的這句話非常精煉,我們從上面這句話中總結如下幾個關鍵詞:

  • 鍵值對
  • 記住插入順序
  • 任意值作為鍵

一看到鍵值對,難免會想到對象。事實確實如此,Map 與我們平常所用的對象非常類似,它是一種類對象的數據結構,所以我們通常稱它為 Map 對象。

但是我們可以把它說得更為官方一點:Map 字典。關於程序中字典的概念大傢可以下去瞭解一下。

特點總結:

  • Map 對象這種數據結構和和對象類型,都已鍵值對的形式存儲數據,即 key-vlue 形式。
  • Map 對象存儲的數據是有序的,而我們平常使用的對象是無序的,所以通常當我們需要使用對象形式(鍵值對)存儲數據且需要有序時,采用 Map 對象進行存儲。
  • Map 對象的鍵值可以是任意類型,我們平時使用的對象隻能使用字符串作為鍵。

1.2 Set(集合)

Map 類似,我們同樣先來看一看官網是怎麼解釋 Set 這個數據結構的。

官網的解釋:

Set 對象允許你存儲任何類型的唯一值,無論是原始值或者是對象引用。

Set 的解釋比 Map 的解釋還要精煉,我們從中提取出幾個關鍵詞:

  • 任何類型
  • 唯一值

上面關鍵詞中我們需要重點關註“唯一值”,這說明使用 Set 存儲的數據是不會重復的,除此之外,Set 也是一個對象,但是它是一個類數組對象,也就是說它長得像數組,我們通常直接稱它為 Set 對象。

當然也可以官方一點的稱它:Set 集合。

特點總結:

  • Set 對象是一個類數組對象,它長得就很像數組。
  • Set 對象存儲的值是不重復的,所以我們通常使用它來實現數組去重。
  • Set 對象存儲的數據不是鍵值對的形式,而且它可以存儲任何類型的數據。

2.基本使用

我們平常使用 Array 或者 Object 的時候,都是直接采用[變量] = [][變量] = {}的形式來進行初始化。而這裡我們所講的 MapSet 數據結構它們都是以構造函數的形式出現的,所以我們通常使用 new Set()或者 new Map()的形式初始化的。

2.1 Map 基本使用

初始化 map 對象:

let myMap = new Map();

初始化 map 時傳入數據:

由於 Map 對象是一個構造函數,所以我們在初始化的時候可以傳入默認數據的,隻不過我們需要註意傳入默認數據的格式,它默認接收一個二維數組。

let defaultMap = new Map([['name', '張三'], ['age', 20]]);

打印出來看看結果:

插入數據:

myMap.set('name', '小豬課堂'); // 字符串作為鍵
myMap.set(12, '會飛的豬'); // number 類型作為鍵
myMap.set({}, '知乎'); // 對象類型作為鍵

我們先打印出來看看結果:

獲取長度:

我們傳統的對象可以通過 Object.key().length 來獲取對象長度,而 map 對象自帶 size 屬性獲取對象長度。

let myMapSize = myMap.size;

獲取值:

let objKey = {};
myMap.set('name', '小豬課堂'); // 字符串作為鍵
myMap.set(12, '會飛的豬'); // number 類型作為鍵
myMap.set(objKey, '知乎'); // 對象類型作為鍵
let name = myMap.get('name');
let age = myMap.get(12);
let any = myMap.get(objKey);
console.log(name, age, any); // 小豬課堂 會飛的豬 知乎

上段代碼中需要註意的是不能使用 myMap.get({})的形式獲取數據,因為 objKey!=={}

刪除某個值:

myMap.delete('name');

判斷某個值是否存在:

myMap.has('name'); // 返回 bool 值

2.2 Set 基本使用

Set對象的使用方式和Map對象的使用方式非常的類似,隻不過存儲的數據格式不一樣罷瞭。這裡需要註意的Set對象存儲的不是鍵值對形式,它隻存儲瞭值,沒有鍵,就和數組類似。

初始化Set對象:

let mySet = new Set();

初始化Set對象帶有默認值:

Map類似,Set初始化時也可以初始化默認數據。

let defaultSet = new Set(['張三', 12, true]);

一起來看看輸出結果:

插入數據:

mySet.add(1);
mySet.add('小豬課堂');

打印結果:

獲取長度:

let mySetSize = mySet.size;

獲取值:

由於Set對象存儲的不是鍵值對形式,所以未提供get方法獲取值,我們通常遍歷它獲取值:

mySet.forEach((item) => {
  console.log(item)
})

刪除某個值:

mySet.delete(1);

判斷某個值是否存在:

mySet.has(1); // 返回Boolean值

3.Map和Set區別

如果我們學會瞭它們兩者如何使用,或多或少都知道它們的區別在哪裡,我們這裡為大傢總結一下它們的區別要點:

  • MapSet查找速度都非常快,時間復雜度為O(1),而數組查找的時間復雜度為O(n)
  • Map對象初始化的值為一個二維數組,Set對象初始化的值為一維數組。
  • Map對象和Set對象都不允許鍵重復(可以將Set對象的鍵想象成值)。
  • Map對象的鍵是不能改的,但是值能改,Set對象隻能通過迭代器來更改值。

4.使用場景介紹

4.1 Set對象使用場景

數組去重

這是大傢很熟悉的一種場景,使用Set對象的唯一性值特性方便的給我們數組去重。

代碼如下:

let arr = [1, 2, 3, 4, 5, 6, 3, 2, 5, 3, 2];
console.log([...new Set(arr)]); // [1, 2, 3, 4, 5, 6]

需要註意的是Set對象是一個類數組,我們使用...擴展運算符將一個類數組轉化為瞭一個真正的數組。

4.2 Map對象使用場景

數字類型充當鍵

代碼如下:

let errors = new Map([
  [400, 'InvalidParameter'],
  [404, 'Not found'],
  [500, 'InternalError']
]);
console.log(errors);

輸出結果:

我們可以使用Map對象建立一個請求狀態碼對象字典,因為狀態碼是數字類型,所以使用Map對象很合適。

除瞭該場景外,如果需要保證對象的順序,那麼也是可以使用Map對象的。

5.思考點

前面我們說SetMap的插入刪除效率為什麼很高呢?

這裡簡單講一下,更加深入需要大傢自己下去好好學習一下數據結構瞭。

簡述原因:

mapset存儲的所有元素都是以節點的方式來進行存儲的,這種節點結構和鏈表有點類似。我們都知道鏈表的特點是插入和刪除都非常快,時間復雜度為O(1),兩個節點通過指針相連,刪除或者增加元素時,我們隻是重新更改瞭指針的指向,不想數組那樣,摻入或刪除之後需要重新排序。

總結

Set對象和Map對象有很多優點的,比如說性能比較好等等,我們需要一一去體會它們的優缺點。你不如在每次創建數據結構之前想一想:使用Object更好還是Map更好呢?使用Array更好還是Set更好呢? 當然,如果深究SetMap底層原理之後,你會發現它們的實現原理就是紅黑樹。

到此這篇關於一文搞懂Map與Set的用法和區別的文章就介紹到這瞭,更多相關Map與Set用法內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: