摘要:前言新增了兩種基本的原生數(shù)據(jù)集合和加上和現(xiàn)在共有四種,以及由兩者衍生出的弱引用集合和。其本身是生成實(shí)例數(shù)據(jù)集合的構(gòu)造函數(shù),可以接受一個(gè)數(shù)組或具有接口的數(shù)據(jù)結(jié)構(gòu)作為參數(shù)用來(lái)初始化。返回鍵值對(duì)的遍歷器對(duì)象,鍵值對(duì)為鍵名鍵值。
前言
ES6新增了兩種基本的原生數(shù)據(jù)集合:Set和Map(加上Array和Object現(xiàn)在共有四種),以及由兩者衍生出的弱引用集合:WeakSet和WeakMap。從某個(gè)不無(wú)狹隘的角度看(不無(wú)狹隘?到底有多狹隘多不狹隘呢?),Set更為類似Array集合的某種提升,而Map則為Object集合的增強(qiáng),雖然兩類在本質(zhì)上就不相同。
1 Set其本身是生成Set實(shí)例(數(shù)據(jù)集合)的構(gòu)造函數(shù),可以接受一個(gè)數(shù)組(或具有iterable接口的數(shù)據(jù)結(jié)構(gòu))作為參數(shù)用來(lái)初始化。存儲(chǔ)的結(jié)構(gòu)類似數(shù)組,不過(guò)成員的值在集合中都是唯一的,不會(huì)出現(xiàn)重復(fù)值。實(shí)際的存儲(chǔ)順序(也是遍歷順序)與插入順序一致,行為的結(jié)果和數(shù)組相同。
其數(shù)據(jù)結(jié)構(gòu)中沒(méi)有鍵名,但為了和Map統(tǒng)一,也可認(rèn)為鍵名和健值是同一值(會(huì)在遍歷小節(jié)中介紹)。內(nèi)部使用的相等判斷規(guī)則,除了認(rèn)為NaN等于NaN,與全等于一致。利用Set中沒(méi)有重復(fù)值的特性,可以簡(jiǎn)單的實(shí)現(xiàn)數(shù)組去重。最后一點(diǎn),其實(shí)例的字符串標(biāo)簽為[Object Set]——厲害啦,都自立了門(mén)戶。
let set = new Set([1, 2]); console.log(...set); // 1 2 console.log({}.toString.call(set)); // [Object Set] let o = {}; [...new Set([1, 2, 2])]; // [1, 2] [...new Set([1, NaN, NaN])]; // [1, NaN] [...new Set([1, o, o])]; // [1, o] [...new Set([1, {}, {}])]; // [1, {}, {}] F(1, {}, 1); // [1, {}],可解析帶遍歷器的類數(shù)組對(duì)象。 function F() { console.log([...new Set(arguments)]); } let o = { length: 0 }; [...new Set(o)]; // 報(bào)錯(cuò),不能自動(dòng)解析不帶遍歷器接口的類數(shù)組對(duì)象。 // 作為簡(jiǎn)單的刪除數(shù)組重復(fù)值的方法。 removeDuplicateValues([1, 2, 2, 3]); // [1, 2, 3] function removeDuplicateValues(arr) { return [...new Set(arr)]; }
關(guān)于相等的小知識(shí)
兩值是否相等一般指的是是否全等,里面有兩個(gè)比較特殊的例子:NaN & NaN和-0 & +0。在全等中,NaN不等于NaN,-0等于+0都為零。但這兩種認(rèn)定在某些場(chǎng)合中不太接地氣,為此ES6給出用于判斷兩值是否相等方法Object.is()中,認(rèn)定NaN等于NaN,-0不等于+0。
0除以1為正零,0除以負(fù)1為負(fù)零,兩者在生成上方式上看的確不應(yīng)該相等。
非數(shù)NaN是一個(gè)不是數(shù)字的數(shù)字(類型依舊為數(shù)字型),沒(méi)有具體的值,因此兩個(gè)NaN是不相等的。不過(guò)在用NaN作為映射中的鍵時(shí),它應(yīng)該代指這一類型而不是具體的個(gè)體。否者我先設(shè)置代碼NaN指向貂蟬,再設(shè)置NaN指代西施,晚上寬衣解帶后發(fā)現(xiàn)仆人竟將兩人同時(shí)安置在被窩之中,笑盈盈水靈靈的。這,讓我如何是好!
2 Map其本身是生成Map實(shí)例(數(shù)據(jù)集合)的構(gòu)造函數(shù),可以接受一個(gè)包含鍵值對(duì)的數(shù)組(或具有iterable接口的數(shù)據(jù)結(jié)構(gòu))作為參數(shù)用來(lái)初始化。簡(jiǎn)單的說(shuō),鍵值對(duì)是包含兩元素的數(shù)組,前者為鍵名后者為鍵值。其存儲(chǔ)的結(jié)構(gòu)類似Object,不會(huì)出現(xiàn)重復(fù)的鍵名,之中使用的相等判定方法與Set一致。其實(shí)例的字符串標(biāo)簽為[Object Map]。
其與對(duì)象主要有兩點(diǎn)不同。一是鍵名,對(duì)象的鍵名只能是字符串或Symbol值,而Map可以是任意類型,它提供了更為完善的值對(duì)值的Hash結(jié)構(gòu)。二是遍歷順序,對(duì)象的遍歷順序大致為先數(shù)值再字符串后Symbol值(會(huì)在遍歷小節(jié)中介紹),而Map是簡(jiǎn)單的與存儲(chǔ)順序保持一致,這在實(shí)際操作中比較有用。
let map = new Map([[1, "one"], [2, "two"]]); console.log(...map); // [1,"one"] [2, "two"] console.log({}.toString.call(map)); // [Object Map] let o = {}; [...new Map([[o, 1], [o, 2]])]; // [[o, 2]] [...new Map([[{}, 1], [{}, 2]])]; // [[{}, 2], [{}, 2]] [...new Map([[null, 1], [undefined, 2]])]; // [[null, 1], [undefined, 2]] let o = { 0: [1, "1"], 1: [2, "2"], length: 2, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; [...new Map(o)]; // [[1, "1"], [2, "2"]]3 實(shí)例方法
關(guān)于Set和Map的完善API請(qǐng)點(diǎn)擊鏈接查看。
這里會(huì)將Set與Map放置在一起,在操作方法和遍歷方法上進(jìn)行異同性說(shuō)明,方便區(qū)分和記憶。另外,為了在方法操作上統(tǒng)一Set與Map,如Set小節(jié)中提及的,我們可以認(rèn)為Set是鍵名與鍵值為同一值的存在(JS本身就是這樣做的)。
3.1 操作方法兩者都有的操作方法
判斷(has),傳入鍵名,返回布爾值。
刪除(delete),傳入鍵名,有且成功刪除為true,否則為false。
清空(clear),無(wú)需傳參,沒(méi)有返回值。
Set獨(dú)有的操作方法
新增(add),傳入值,返回實(shí)例本身。
沒(méi)有相應(yīng)的獲取方法,因?yàn)楂@取需傳入的值就是應(yīng)所傳出的值。
let set = new Set(); set.add(1).add(NaN); // set.size 為 2。 set.has(NaN); // true set.delete(NaN); // true set.has(NaN); // false set.delete(2); // false set.clear(); console.log(...set); // 它變得一無(wú)所有,只剩一具空殼。
Map獨(dú)有的操作方法
新增(set),傳入鍵名和鍵值,有則更新沒(méi)則新增,返回實(shí)例本身。
獲取(get),傳入鍵名,返回相應(yīng)值沒(méi)有則為undefined。
let o = [1, 2, 3]; let map = new Map(); map.set(o, 1).set(o, 2); // map.size 為 1 map.has(o); // true map.get(o); // 2 map.get([1, 2, 3]); // undefined map.delete(o); // true map.clear(); console.log(...map); // 它再次一無(wú)所有,只剩愈發(fā)饑渴的獸心。3.2 遍歷方法
返回鍵名的遍歷器對(duì)象(keys)。
返回鍵值的遍歷器對(duì)象(values)。
返回鍵值對(duì)的遍歷器對(duì)象(entries),鍵值對(duì)為[鍵名, 鍵值]。
遍歷每個(gè)成員(forEach),使用方式與Array的方法相同。
因?yàn)?b>Set的鍵名和鍵值相同,所以一般只使用values方法獲取全部值。而Map則根據(jù)相應(yīng)需求獲取即可。
let set = new Set([1, 2, 3]); let map = new Map([[1, "one"], [null, NaN]]); [...set.values()]; // [1, 2, 3] [...set.keys()]; // [1, 2, 3] [...set.entries()]; // [[1, 1], [2, 2], [3, 3]] [...map.values()]; // ["one", NaN] [...map.keys()]; // [1, null] [...map.entries()]; // [[1, "one"], [null, NaN]]
兩者的forEach方法與數(shù)組的不同點(diǎn)在于回調(diào)函數(shù)的第二個(gè)參數(shù),前者為該項(xiàng)的鍵名后者為該項(xiàng)的序號(hào)。
let set = new Set([1, 2, 3]); let map = new Map([[1, "one"], [null, NaN]]); set.forEach((v, i) => console.log(i)); // 1, 2, 3 map.forEach((v, i) => console.log(i)); // 1, null [1, 2, 3].forEach((v, i) => console.log(i)); // 0, 1, 2
對(duì)象屬性的遍歷順序
不同遍歷對(duì)象的方法面向的數(shù)據(jù)種類不同,但總的說(shuō)其遍歷順序是這樣的:先找到其中可轉(zhuǎn)化成數(shù)值的屬性并按升序遍歷,再遍歷字符串屬性按加入時(shí)間的前后,最后遍歷Symbol值按加入時(shí)間的前后。Map的遍歷順序即其被插入時(shí)的順序,嗯,總有些色咪咪的味道。
let obj = { "0": 0, 1: 1, "b": 2, "a": 3, [Symbol(2)]: 4, [Symbol(1)]: 5 }; Reflect.ownKeys(obj); // ["0", "1", "b", "a", Symbol(2), Symbol(1)]4 弱引用集合
弱引用集合WeakSet和WeakMap是由Set和Map分別衍生出的,其與本體的異同點(diǎn)一致,因此只對(duì)WeakMap進(jìn)行說(shuō)明。
在JS的垃圾回收機(jī)制中,對(duì)象會(huì)在沒(méi)有引用時(shí)(可意為使用)被回收。這說(shuō)明著,如果有個(gè)數(shù)據(jù)集合(數(shù)組、對(duì)象、Set或Map)中包含了某對(duì)象(在使用它),那么在此數(shù)據(jù)集合被回收之前該對(duì)象都不能被回收。這很容易導(dǎo)致內(nèi)存泄漏(專有名詞,可簡(jiǎn)單理解為內(nèi)存被沒(méi)用的數(shù)據(jù)占據(jù))。
弱引用集合的設(shè)計(jì)目的就是為了解決這個(gè)問(wèn)題。弱引用顧名思義是指雖然某對(duì)象被此集合引用了,但該引用不被引擎保護(hù),不被垃圾回收裝置考慮在內(nèi),該回收時(shí)就得乖乖的被回收。那些被慣成畸形的家伙們,要知道,媽媽的懷抱可不是個(gè)萬(wàn)全的地方哦,唯有死神的才是。
WeakMap的行為與Map除了以下幾點(diǎn)不同外,可以認(rèn)為是一致的。
WeakMap的鍵名只能是對(duì)象(不包括null),否者報(bào)錯(cuò)。如果能放入普通類型,那有什么意義呢?
WeakMap的鍵名是動(dòng)態(tài)不定的,不知道什么時(shí)候會(huì)被回收。鍵名指代的對(duì)象被回收后,該項(xiàng)會(huì)被自動(dòng)消除。
因?yàn)轫?xiàng)數(shù)的動(dòng)態(tài)性,所以不能被遍歷(沒(méi)有遍歷方法),沒(méi)有size屬性,沒(méi)有cealr方法。
let o = {}; let wm = new WeakMap(); wm.set(1, 1); // 報(bào)錯(cuò),1 不是對(duì)象。 wm.set(o, 1); wm.has(o); // true wm.get(o); // 1 wm.delete(o); // true "size" in wm; // false "clear" in wm; // false "values" in wm; // false
弱引用集合的優(yōu)點(diǎn)在于,我們可以任意為其注冊(cè)對(duì)象,而不用擔(dān)心內(nèi)存泄漏。典型的應(yīng)用場(chǎng)景是將DOM與數(shù)據(jù)進(jìn)行綁定。一些要在DOM中綁定數(shù)據(jù)的庫(kù)中,比如d3,會(huì)直接在DOM對(duì)象上設(shè)置屬性進(jìn)行保存。但在日常組建單頁(yè)面程序中的某個(gè)階段,想將DOM與數(shù)據(jù)聯(lián)系在一起時(shí),我們顯然會(huì)優(yōu)先選用數(shù)據(jù)映射的方式。而弱引用集合的出現(xiàn),更加優(yōu)化了這種方式。
在下面的示例中,每次點(diǎn)擊請(qǐng)求數(shù)據(jù)后都會(huì)生成幫了相應(yīng)數(shù)據(jù)項(xiàng)的li標(biāo)簽,并將該標(biāo)簽與相應(yīng)的數(shù)據(jù)進(jìn)行綁定。在這一系列輪回存儲(chǔ)綁定中,因?yàn)?b>WeakMap的弱引用特性,我們不需要關(guān)心已經(jīng)被刪除的DOM元素。每次只需進(jìn)行相同的操作,方便安心,省時(shí)省力。
ES6精華:Symbol
ES6精華:解構(gòu)賦值
ES6精華:函數(shù)擴(kuò)展
ES6精華:Proxy & Reflect
Iterator:訪問(wèn)數(shù)據(jù)集合的統(tǒng)一接口
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96801.html
摘要:虛擬機(jī)所處的區(qū)域,則表示它是屬于新生代收集器還是老年代收集器。虛擬機(jī)總共運(yùn)行了分鐘,其中垃圾收集花掉分鐘,那么吞吐量就是。收集器線程所占用的數(shù)量為。 本文主要從GC(垃圾回收)的角度試著對(duì)jvm中的內(nèi)存分配策略與相應(yīng)的垃圾收集器做一個(gè)介紹。 注:還是老規(guī)矩,本著能畫(huà)圖就不BB原則,盡量將各知識(shí)點(diǎn)通過(guò)思維導(dǎo)圖或者其他模型圖的方式進(jìn)行說(shuō)明。文字僅記錄額外的思考與心得,以及其他特殊情況 內(nèi)存...
摘要:常被用來(lái)檢查對(duì)象中是否存在某個(gè)鍵名,集合常被用來(lái)獲取已存的信息。返回一個(gè)布爾值,表示該值在中存在與否。集合存放對(duì)象的弱引用,當(dāng)該對(duì)象的其他強(qiáng)引用被清除時(shí),集合中的弱引用也會(huì)自動(dòng)被垃圾回收機(jī)制回收,追蹤成組的對(duì)象是該集合最好的使用方式。 Map和Set都叫做集合,但是他們也有所不同。Set常被用來(lái)檢查對(duì)象中是否存在某個(gè)鍵名,Map集合常被用來(lái)獲取已存的信息。 Set Set是有序列表,含...
摘要:返回一個(gè)布爾值,表示該值是否為的成員。返回鍵名的遍歷器返回鍵值的遍歷器返回鍵值對(duì)的遍歷器使用回調(diào)函數(shù)遍歷每個(gè)成員需要特別指出的是,的遍歷順序就是插入順序。該數(shù)組的所有成員,都會(huì)自動(dòng)成為實(shí)例對(duì)象的成員。這意味著,數(shù)組的成員只能是對(duì)象。 1.Set ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類似于數(shù)組,但是成員的值都是唯一的,沒(méi)有重復(fù)的值。Set 本身是一個(gè)構(gòu)造函數(shù),用來(lái)生成 Set 數(shù)據(jù)結(jié)構(gòu)...
摘要:返回一個(gè)布爾值,表示該值是否為的成員。清除所有成員,沒(méi)有返回值。返回的都是遍歷器對(duì)象。結(jié)構(gòu)的實(shí)例的方法,用于對(duì)每個(gè)成員執(zhí)行某種操作,沒(méi)有返回值。這個(gè)特點(diǎn)意味著,無(wú)法引用的成員,因此是不可遍歷的。數(shù)組成員是一個(gè)或多個(gè)表示鍵值對(duì)的一維數(shù)組。 本文字?jǐn)?shù):4700+,閱讀時(shí)間約10分鐘。 如果有理解不到位的地方,歡迎大家糾錯(cuò)。 一、Set 【01】Set是一種數(shù)據(jù)結(jié)構(gòu)。類似于數(shù)組,但是成員的值...
閱讀 1305·2021-11-16 11:44
閱讀 3773·2021-10-09 10:01
閱讀 1764·2021-09-24 10:31
閱讀 3851·2021-09-04 16:41
閱讀 2525·2021-08-09 13:45
閱讀 1224·2019-08-30 14:08
閱讀 1789·2019-08-29 18:32
閱讀 1650·2019-08-26 12:12