第十七节:ES6新增的Map和WeakMap 又是什么东西?
????????上節(jié)介紹了Set和WeakSet,這節(jié)咱就講Map和WeakMap是什么?當(dāng)然,兩者之前并沒什么必然的聯(lián)系,僅僅是用法類似。
什么是Map
????????介紹什么是Map,就不得不說(shuō)起Object對(duì)象,我們都知道Object對(duì)象是鍵值對(duì)的集合:
? ?//Object對(duì)象
? ?{"name":"前端君","gender":1}
????????ES5中的key鍵名的類型要求一定是字符串,當(dāng)然,ES6已經(jīng)允許屬性名的類型是Symbol,第十一節(jié)有講解,可點(diǎn)擊查看。
????????現(xiàn)在,ES6 提供了Map結(jié)構(gòu)給我們使用,它跟Object對(duì)象很像,但是不同的是,它的key鍵名的類型不再局限于字符串類型了,它可以是各種類型的值;可以說(shuō),它比Object對(duì)象更加靈活了,當(dāng)然,也更加復(fù)雜了。
?
Map的基本用法
????????知道了什么是Map,我們接著來(lái)學(xué)學(xué)它的基本用法,看看它是怎么使用的。
????????Map結(jié)構(gòu)提供了一個(gè)構(gòu)造函數(shù)給我們,我們使用的時(shí)候需要用new來(lái)創(chuàng)建實(shí)例:
? ?let m = new Map();
????????如果想要在創(chuàng)建實(shí)例的同時(shí),初始化它的內(nèi)容,我們可以給它傳參,形式跟Set結(jié)構(gòu)類型,都是需要用數(shù)組作為參數(shù),我們來(lái)試試看看:
? ?let m = new Map([
? ? ? ? ? ?["name","前端君"],
? ? ? ? ? ?["gender",1]
? ?]);
? ?
? ?console.log(m);
? ?//打印結(jié)果:Map {"name" => "前端君", "gender" => 1}
????????大家注意Map( )方法里面的參數(shù),首先它是一個(gè)數(shù)組,而里面的內(nèi)容也是由多個(gè)數(shù)組組成,“name”:“前端君”作為一個(gè)鍵值對(duì),將它們裝在一個(gè)數(shù)組里面,[“name”:“前端君”],另外一組鍵值對(duì)也一樣:[“gender”:1 ]。這就是初始化一個(gè)Map結(jié)構(gòu)實(shí)例的基本寫法。
?
????????初始化成實(shí)例后,Map結(jié)構(gòu)還提供了一些實(shí)例的屬性和方法供我們實(shí)現(xiàn)對(duì)實(shí)例的操作。我們一起看看都有哪些屬性和方法。?
set( )方法
????????set( )方法作用:給實(shí)例設(shè)置一對(duì)鍵值對(duì),返回map實(shí)例。
? ?let m = new Map();
? ?//set方法添加
? ?//添加一個(gè)string類型的鍵名
? ?m.set("name","前端君"); ?
?
? ?//添加一個(gè)數(shù)字類型的鍵名
? ?m.set(1,2);
? ?console.log(m);
? ?//打印結(jié)果:Map {"name" => "前端君", 1 => 2}
????????set方法的使用很簡(jiǎn)單,只需要給方法傳入key和value作為鍵名和鍵值即可。注意:第三行代碼中,我們傳入的key是數(shù)字1,這就證明了,Map結(jié)構(gòu)確實(shí)可以存儲(chǔ)非字符串類型的鍵名,當(dāng)然你還可以設(shè)置更多其它類型的鍵名,比如:
? ?//數(shù)組類型的鍵名
? ?m.set([1],2);
? ?//對(duì)象類型的鍵名
? ?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種類型值都可以作為鍵名,可以成功添加鍵值對(duì),沒毛病。
????????使用set方法的時(shí)候有一點(diǎn)需要注意,如果你設(shè)置一個(gè)已經(jīng)存在的鍵名,那么后面的鍵值會(huì)覆蓋前面的鍵值。我們演示一下:
? ?let m = new Map();
? ?m.set("name","前端君");
? ?console.log(m);
? ?//結(jié)果:Map {"name" => "前端君"}
? ?//再次設(shè)置name的值
? ?m.set("name","隔壁老王");
? ?console.log(m);
? ?//結(jié)果:Map {"name" => "隔壁老王"}
????????上面的案例,我們第一次把name的值設(shè)置為“前端君”,當(dāng)再次使用set方法設(shè)置name的值的時(shí)候,后者成功覆蓋了前者的值,從此“前端君” 變 “隔壁老王”。
get( )方法
????????get( )方法作用:獲取指定鍵名的鍵值,返回鍵值。
? ?let m = new Map([["name","前端君"]]);
? ?m.get("name");//結(jié)果:前端君
? ?m.get("gender");//結(jié)果:undefined
????????get方法使用也很簡(jiǎn)單,只需要指定鍵名即可。獲取存在對(duì)應(yīng)的鍵值,如果鍵值對(duì)存在,就會(huì)返回鍵值;否則,返回undefined,這個(gè)也很好理解。
?
delete( )方法
????????delete( )方法作用:刪除指定的鍵值對(duì),刪除成功返回:true,否則返回:false。
? ?let m = new Map();
? ?m.set("name","前端君");
? ?//結(jié)果:Map {"name" => "前端君"}
? ?m.delete("name");//結(jié)果:true
? ?m.delete("gender");//結(jié)果:false
????????我們使用delete方法,刪除“name”的時(shí)候成功,返回了true。刪除“gender”的時(shí)候,由于Map結(jié)構(gòu)中不存在鍵名:“gender”,所以刪除失敗,返回false。
?
clear( )方法
????????跟Set結(jié)構(gòu)一樣,Map結(jié)構(gòu)也提供了clear( )方法,讓你一次性刪除所有鍵值對(duì)。
? ?let m = new Map();
? ?m.set("name","前端君");
? ?m.set("gender",1);
? ?m.clear();
? ?console.log(m);
? ?//打印結(jié)果:Map {}
????????使用clear方法后,我們?cè)俅蛴∫幌伦兞縨,發(fā)現(xiàn)什么都沒有,一個(gè)空的Map結(jié)構(gòu),說(shuō)明clear方法起作用了。
?
has( )方法
????????has( )方法作用:判斷Map實(shí)例內(nèi)是否含有指定的鍵值對(duì),有就返回:true,否則返回:false。
? ?let m = new Map();
? ?m.set("name","前端君");
? ?m.has('name');//結(jié)果:true
? ?m.has('age');//結(jié)果:false
????????Map實(shí)例中含有鍵名:name,就返回了true,鍵名age不存在,就返回false。好理解吧,比較簡(jiǎn)單。
?
可遍歷
????????Object對(duì)象能被for...in遍歷,Map結(jié)構(gòu)也不示弱,同樣可以被遍歷。我們可以使用ES6的新特性for...of來(lái)遍歷它的鍵名或者鍵值。
entries( )方法
????????entries( )方法作用:返回實(shí)例的鍵值對(duì)遍歷器。
????????我們?cè)诘谑?jié)說(shuō)過(guò),for...of可以遍歷具有遍歷器接口的對(duì)象。那么,我們就結(jié)合for...of來(lái)演示一下Map結(jié)構(gòu)的遍歷。
? ?let m = new Map([
? ? ? ? ? ?["name","前端君"],
? ? ? ? ? ?["age",25]
? ?]);
? ?for(let [key,value] of m.entries()){
??? ? ? console.log(key+'? '+value);
? ?}
? ?//打印結(jié)果:name? 前端君
? ?//???????? ? ? ?age? 25
? ?
????????案例中的 m.entries( ) 返回鍵值對(duì)的遍歷器,使用了for...of來(lái)遍歷這個(gè)遍歷器,得到的值分別賦值到key和value,然后控制臺(tái)分別輸出它們。
???????? 還記得嗎?上一節(jié)中,介紹Set結(jié)構(gòu)的遍歷的時(shí)候,也是這樣的遍歷方式。
?
keys( ) 和 values( ) 方法
????????keys( )方法:返回實(shí)例所有鍵名的遍歷器。
????????values( ) 方法:返回實(shí)例所有鍵值的遍歷器。
????????既然都是遍歷器,那就用for...of把它們遍歷出來(lái)吧:
? ?? ?let m = new Map([
? ? ? ?["name","前端君"],
? ? ? ?["age",25]
? ?]);
? ?//使用keys方法獲取鍵名
? ?for(let key of m.keys()){
??? ? ? console.log(key);
? ?}
? ?//打印結(jié)果:name
? ?//??????? ? ? ? ?? age
? ?//使用values方法獲取鍵值
? ?for(let value of m.values()){
??? ? ? console.log(value);
? ?}
? ?//打印結(jié)果:前端君
? ?//??????? ? ? ? ?? 25
? ?
????????
????????keys方法和values方法的使用方式一致,只是返回的結(jié)果不同。
?
forEach( )方法
????????除了使用以上三個(gè)方法實(shí)現(xiàn)遍歷以外,我們還可以使用forEach遍歷每一個(gè)鍵值對(duì):
? ?? ?let m = new Map([
? ? ? ?["name","前端君"],
? ? ? ?["age",25]
? ?]);
? ?
? ?m.forEach(function(value,key){
??? ? ? console.log(key+':'+value);
? ?});
? ?//打印結(jié)果:name:前端君
? ?//???????? ? ? ? ? age:25
? ?
????????forEach方法接收一個(gè)匿名函數(shù),給匿名函數(shù)傳參value和key,分別是Map實(shí)例的鍵名和鍵值,這個(gè)方法的使用相信大家一定不會(huì)陌生。
size屬性
????????其中一個(gè)常用的屬性就是size:獲取實(shí)例的成員數(shù)。
? ?let m = new Map();
? ?m.set(1,3);
? ?m.set('1','3');
? ?m.size;//結(jié)果:2
????????使用set方法給實(shí)例m添加了兩個(gè)鍵值對(duì)成員,所以實(shí)例的 size為:2。
?
什么是WeakMap
????????講了Map結(jié)構(gòu),我們現(xiàn)在講WeakMap結(jié)構(gòu)。
????????WeakMap結(jié)構(gòu)和Map結(jié)構(gòu)很類似,不同點(diǎn)在于WeakMap結(jié)構(gòu)的鍵名只支持引用類型的數(shù)據(jù)。哪些是引用類型的值呢?比如:數(shù)組,對(duì)象,函數(shù)。
????????關(guān)于什么是引用類型,其中涉及到了傳址和傳值的區(qū)別,還記得裝修工張師傅和王師傅的例子嗎?第三節(jié)有詳細(xì)的講解,點(diǎn)擊可查看。
?
WeakMap的基本用法???
????????WeakMap結(jié)構(gòu)的使用方式和Map結(jié)構(gòu)一樣:
? ?let wm = new WeakMap();
????????兩者都是使用new來(lái)創(chuàng)建實(shí)例。如果添加鍵值對(duì)的話,我們同樣是使用set方法,不過(guò)鍵名的類型必須要求是引用類型的值,我們來(lái)看看:
? ?let wm = new WeakMap();
? ?//數(shù)組類型的鍵名
? ?wm.set([1],2);
? ?//對(duì)象類型的鍵名
? ?wm.set({'name':'Zhangsan'},2);
? ?//函數(shù)類型的鍵名
? ?function fn(){};
? ?wm.set(fn,2);
? ?console.log(wm);
? ?//打印:WeakMap {
? ? ? ? ? ?[1] => 2,
? ? ? ? ? ?Object {name: "Zhangsan"} => 2,
? ? ? ? ? ?function => 2
? ? ? ? ? ?}
? ? ? ? ? ? ? ?
????????從打印結(jié)果可以看出,以上類型的鍵名都可以成功添加到WeakMap實(shí)例中。?
WeakMap和Map的區(qū)別
????????如果是普通的值類型則不允許。比如:字符串,數(shù)字,null,undefined,布爾類型。而Map結(jié)構(gòu)是允許的,這就是兩者的不同之處,謹(jǐn)記。
????????跟Map一樣,WeakMap也擁有g(shù)et、has、delete方法,用法和用途都一樣。不同地方在于,WeakMap不支持clear方法,不支持遍歷,也就沒有了keys、values、entries、forEach這4個(gè)方法,也沒有屬性size。
????????理由跟WeakSet結(jié)構(gòu)一樣:鍵名中的引用類型是弱引用,你永遠(yuǎn)不知道這個(gè)引用對(duì)象什么時(shí)候會(huì)被垃圾回收機(jī)制回收了,如果這個(gè)引用類型的值被垃圾機(jī)制回收了,WeakMap實(shí)例中的對(duì)應(yīng)鍵值對(duì)也會(huì)消失。
本節(jié)小結(jié)
????
總結(jié):Map結(jié)構(gòu)是一個(gè)鍵值對(duì)的集合,跟Object對(duì)象不同的是,Map結(jié)構(gòu)的鍵名可以是任何類型的值,而WeakMap結(jié)構(gòu)的鍵名只允許是引用類型的值。
????????它們都提供了各自的方法和屬性供開發(fā)者使用:set、get、has、delete等相同的方法,其中Map結(jié)構(gòu)還多了clear方法,size屬性和一些用于遍歷的方法:keys、values、entries、forEach。
總結(jié)
以上是生活随笔為你收集整理的第十七节:ES6新增的Map和WeakMap 又是什么东西?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [云炬创业基础笔记]第五章创业机会评估测
- 下一篇: [云炬创业基础笔记]第五章创业机会评估测