1. 程式人生 > >ES6新增的Map和WeakMap 又是什麼玩意?非常詳細的解釋

ES6新增的Map和WeakMap 又是什麼玩意?非常詳細的解釋

上一篇文章講了set和weakSet,這節咱就講Map和weakMap是什麼?這兩篇文章並沒有什麼聯絡,主要知識用法類似而已.嘿嘿,是不是感覺舒服多了.

什麼是Map

介紹什麼是Map,就不得不說起Object物件,我們都知道Object物件是鍵值對的集合:

//Object物件
    {"name":"前端君","gender":1}

 

ES5中的key鍵名的型別要求一定是字串,當然,ES6已經允許屬性名的型別是Symbol,前面的文章有所講解

現在,ES6 提供了Map結構給我們使用,它跟Object物件很像,但是不同的是,它的key鍵名的型別不再侷限於字串型別了,它可以是各種型別的值;可以說,它比Object物件更加靈活了,當然,也更加複雜了。

Map的基本用法

知道了什麼是Map,我們接著來學學它的基本用法,看看它是怎麼使用的。

Map結構提供了一個建構函式給我們,我們使用的時候需要用new來建立例項:

  let m = new Map();

 

如果想要在建立例項的同時,初始化它的內容,我們可以給它傳參,形式跟Set結構型別,都是需要用陣列作為引數,我們來試試看看:

 let m = new Map([
            ["name","前端君"],
            ["gender",1]
    ]);
    
    console.log(m);
    //列印結果:Map {"name" => "前端君", "gender" => 1}

 

大家注意Map( )方法裡面的引數,首先它是一個數組,而裡面的內容也是由多個數組組成,“name”:“前端君”作為一個鍵值對,將它們裝在一個數組裡面,[“name”:“前端君”],另外一組鍵值對也一樣:[“gender”:1 ]。這就是初始化一個Map結構例項的基本寫法。

初始化成例項後,Map結構還提供了一些例項的屬性和方法供我們實現對例項的操作。我們一起看看都有哪些屬性和方法。

set( )方法

set( )方法作用:給例項設定一對鍵值對,返回map例項。

let m = new Map();
    //set方法新增

    //新增一個string型別的鍵名
    m.set("name","前端君");  
  
    //新增一個數字型別的鍵名
    m.set(1,2);

    console.log(m);
    //列印結果:Map {"name" => "前端君", 1 => 2}

 

set方法的使用很簡單,只需要給方法傳入key和value作為鍵名和鍵值即可。注意:第三行程式碼中,我們傳入的key是數字1,這就證明了,Map結構確實可以儲存非字串型別的鍵名,當然你還可以設定更多其它型別的鍵名,比如:

//陣列型別的鍵名
    m.set([1],2);

    //物件型別的鍵名
    m.set({"name":"Zhangsan"},2);

    //布林型別的鍵名
    m.set(true,2);

    //Symbol型別的鍵名
    m.set(Symbol('name'),2);

    //null為鍵名
    m.set(null,2);

    //undefined為鍵名
    m.set(undefined,2);

 

以上6種類型值都可以作為鍵名,可以成功新增鍵值對,沒毛病。

使用set方法的時候有一點需要注意,如果你設定一個已經存在的鍵名,那麼後面的鍵值會覆蓋前面的鍵值。我們演示一下:

 let m = new Map();
    m.set("name","前端君");
    console.log(m);
    //結果:Map {"name" => "前端君"}

    //再次設定name的值
    m.set("name","隔壁老王");
    console.log(m);
    //結果:Map {"name" => "隔壁老王"}

 

上面的案例,我們第一次把name的值設定為“前端君”,當再次使用set方法設定name的值的時候,後者成功覆蓋了前者的值,從此“前端君” 變 “隔壁老王”。

get( )方法

get( )方法作用:獲取指定鍵名的鍵值,返回鍵值。

let m = new Map([["name","前端君"]]);

    m.get("name");//結果:前端君
    m.get("gender");//結果:undefined

 

get方法使用也很簡單,只需要指定鍵名即可。獲取存在對應的鍵值,如果鍵值對存在,就會返回鍵值;否則,返回undefined,這個也很好理解。

delete( )方法

delete( )方法作用:刪除指定的鍵值對,刪除成功返回:true,否則返回:false。

let m = new Map();
    m.set("name","前端君");
    //結果:Map {"name" => "前端君"}

    m.delete("name");//結果:true
    m.delete("gender");//結果:false

 

我們使用delete方法,刪除“name”的時候成功,返回了true。刪除“gender”的時候,由於Map結構中不存在鍵名:“gender”,所以刪除失敗,返回false。

clear( )方法

跟Set結構一樣,Map結構也提供了clear( )方法,讓你一次性刪除所有鍵值對。

 let m = new Map();
    m.set("name","前端君");
    m.set("gender",1);

    m.clear();
    console.log(m);
    //列印結果:Map {}

 

使用clear方法後,我們再列印一下變數m,發現什麼都沒有,一個空的Map結構,說明clear方法起作用了。

has( )方法

has( )方法作用:判斷Map例項內是否含有指定的鍵值對,有就返回:true,否則返回:false。

 let m = new Map();
    m.set("name","前端君");

    m.has('name');//結果:true
    m.has('age');//結果:false

 

Map例項中含有鍵名:name,就返回了true,鍵名age不存在,就返回false。好理解吧,比較簡單。

可遍歷

Object物件能被for...in遍歷,Map結構也不示弱,同樣可以被遍歷。我們可以使用ES6的新特性for...of來遍歷它的鍵名或者鍵值。

entries( )方法

entries( )方法作用:返回例項的鍵值對遍歷器。

我們在第十三節說過,for...of可以遍歷具有遍歷器介面的物件。那麼,我們就結合for...of來演示一下Map結構的遍歷。

let m = new Map([
            ["name","前端君"],
            ["age",25]
    ]);

    for(let [key,value] of m.entries()){
        console.log(key+'  '+value);
    }
    //列印結果:name  前端君
    //              age  25
    

 

案例中的 m.entries( ) 返回鍵值對的遍歷器,使用了for...of來遍歷這個遍歷器,得到的值分別賦值到key和value,然後控制檯分別輸出它們。

還記得嗎?上一節中,介紹Set結構的遍歷的時候,也是這樣的遍歷方式。

keys( ) 和 values( ) 方法

keys( )方法:返回例項所有鍵名的遍歷器。

values( ) 方法:返回例項所有鍵值的遍歷器。

既然都是遍歷器,那就用for...of把它們遍歷出來吧:

 let m = new Map([
        ["name","前端君"],
        ["age",25]
    ]);

    //使用keys方法獲取鍵名
    for(let key of m.keys()){
        console.log(key);
    }
    //列印結果:name
    //                 age

    //使用values方法獲取鍵值
    for(let value of m.values()){
        console.log(value);
    }
    //列印結果:前端君
    //                 25
    

 

keys方法和values方法的使用方式一致,只是返回的結果不同。

forEach( )方法

除了使用以上三個方法實現遍歷以外,我們還可以使用forEach遍歷每一個鍵值對:

let m = new Map([
        ["name","前端君"],
        ["age",25]
    ]);
    
    m.forEach(function(value,key){
        console.log(key+':'+value);
    });
    //列印結果:name:前端君
    //                 age:25
    

 

forEach方法接收一個匿名函式,給匿名函式傳參value和key,分別是Map例項的鍵名和鍵值,這個方法的使用相信大家一定不會陌生。

size屬性

其中一個常用的屬性就是size:獲取例項的成員數。

 let m = new Map();
    m.set(1,3);
    m.set('1','3');

    m.size;//結果:2

 

使用set方法給例項m添加了兩個鍵值對成員,所以例項的 size為:2。

什麼是WeakMap

講了Map結構,我們現在講WeakMap結構。

WeakMap結構和Map結構很類似,不同點在於**WeakMap結構的鍵名只支援引用型別的資料。**哪些是引用型別的值呢?比如:陣列,物件,函式。

關於什麼是引用型別,其中涉及到了傳址和傳值的區別,還記得裝修工張師傅和王師傅的例子嗎?第三節有詳細的講解,點選可檢視。

WeakMap的基本用法

WeakMap結構的使用方式和Map結構一樣:

 let wm = new WeakMap();

 

兩者都是使用new來建立例項。如果新增鍵值對的話,我們同樣是使用set方法,不過鍵名的型別必須要求是引用型別的值,我們來看看:

 let wm = new WeakMap();

    //陣列型別的鍵名
    wm.set([1],2);

    //物件型別的鍵名
    wm.set({'name':'Zhangsan'},2);

    //函式型別的鍵名
    function fn(){};
    wm.set(fn,2);

    console.log(wm);
    //列印:WeakMap {
            [1] => 2, 
            Object {name: "Zhangsan"} => 2, 
            function => 2
            }

 

從列印結果可以看出,以上型別的鍵名都可以成功新增到WeakMap例項中。

WeakMap和Map的區別

如果是普通的值型別則不允許。比如:字串,數字,null,undefined,布林型別。而Map結構是允許的,這就是兩者的不同之處,謹記。

跟Map一樣,WeakMap也擁有get、has、delete方法,用法和用途都一樣。不同地方在於,WeakMap不支援clear方法,不支援遍歷,也就沒有了keys、values、entries、forEach這4個方法,也沒有屬性size。

理由跟WeakSet結構一樣:鍵名中的引用型別是弱引用,你永遠不知道這個引用物件什麼時候會被垃圾回收機制回收了,如果這個引用型別的值被垃圾機制回收了,WeakMap例項中的對應鍵值對也會消失。

本節小結

總結:Map結構是一個鍵值對的集合,跟Object物件不同的是,Map結構的鍵名可以是任何型別的值,而WeakMap結構的鍵名只允許是引用型別的值。

它們都提供了各自的方法和屬性供開發者使用:set、get、has、delete等相同的方法,其中Map結構還多了clear方法,size屬性和一些用於遍歷的方法:keys、values、entries、forEach。
更多前端學習內容文章乾貨請關注我的專欄(不斷更新)

阿里名廠標準web前端高階工程師教程目錄大全,從基礎到進階,看完保證您的薪資上升一個臺階

在這裡我給大家準備了很多的學習資料
其實你與阿里工程師的差距只差這些東西