本文做爲ES6入門第十三章的學習整理筆記,可能會包含少部分我的的理解推測,若想閱讀更詳細的介紹,還請閱讀原文ES6入門es6
1、set數據結構數組
1.set不接受重複值數據結構
ES6新增了Set構造函數用於建立set數據結構,這種結構相似於數組,但有很大的一個區別就是,set數據結構不接受重複值,每一個值都是惟一的。dom
咱們能夠經過Set構造函數快速建立一個set數據結構,順便打印看看究竟長什麼樣:函數
let s = new Set(); console.dir(s);
那麼能夠看到,set實例具備一個size屬性,由於咱們還未給此結構添加值,因此是0,相似於數組的length屬性。學習
set實例還有不少方法,例如add添加,clear清除,還有在數組拓展中已經介紹過的keys,values等比較熟悉的方法,這些後面具體再說。spa
咱們嘗試在new命令時直接初始化值:prototype
let s = new Set([1,2,1,3]);
能夠看到,儘管我添加了兩個數字1,最終的set實例結構中只有一個不重複的1,這是由於set不接受重複的值,自帶去重效果。code
你可能看過如下數組去重的快捷方法,正式利用的set的這一特色:對象
// 數組去重 [...new Set([1, 1, 2, 3, 4, 4])]; Array.from(new Set([1, 1, 2, 3, 4, 4]));
2.set實例的增刪改查方法
add方法:添加某個值,返回添加值後的set解構,相似數組的push,後添加的元素在set解構後面。
let s = new Set(); s.add(1).add(2);
has方法:查找set解構是否包含某值,返回一個布爾值。
s.has(1); //true s.has(3); //false
delete方法:刪除某個值,返回一個布爾值對應是否刪除成功。
s.delete(1);//true s.delete(1);//false
clear方法:清除整個set解構,無返回值。
s.clear();
3.set的遍歷方法
keys方法:遍歷元素的鍵名
values方法:遍歷元素的鍵值
entries方法:遍歷元素的鍵值對
forEach方法:用的賊多,回調函數遍歷每一個元素
在數組拓展這一章節中也有介紹這三個方法,這裏就簡單說下;三個方法都是結合for...of循環使用,分別遍歷元素的key,value與key/value組合。
let s = new Set([{a:1}, {b:2}, {c:3}]); for (let item of s.keys()) { console.log(item);// {a:1}, {b:2}, {c:3} }; for (let item of s.values()) { console.log(item);// {a:1}, {b:2}, {c:3} }; for (let item of s.entries()) { console.log(item);// [{a:1},{a:1}],[{b:2},{b:2}],[{c:3},{c:3}] };
經過上述代碼中的輸出能夠了解到,keys方法與values方法執行徹底相同,這是由於set解構沒有key名致使,key名與value相同;而entries方法每次返回的是一個包含了key與value的數組。
當咱們想遍歷出set解構的每一個元素理論上使用values方法,有趣的是set解構的默認遍歷器恰好與values相等,因此咱們甚至能省略掉values方法直接遍歷解構中的每一個元素。
let s = new Set([1, 2, 3]); Set.prototype[Symbol.iterator] === Set.prototype.values; //true //省略values方法 for(let item of s){ console.log(item);//1 2 3 };
與數組中使用這三個方法的區別在於,數組中的keys遍歷的是元素的下標,values相同,entries是下標和元素組成鍵值對,且不是數組。
當咱們使用forEach遍歷set結構數據時,回調參數三個參數的前兩個徹底相同,這也是由於key名與key值相同的緣故,這點須要注意。
let s = new Set([1, 2, 3]); s.forEach((val,key) => console.log(val,key))//1 1,2 2,3 3
4.set解構的做用
a.數組去重,主要利用了set不接受重複值作參數的特色。
b.set結構實現並集,簡單點說,就是把兩個set重複項去掉,原理仍是利用set不接受重複項
let a = new Set([1, 2, 3]); let b = new Set([2, 3, 4]); let s1 = new Set([...a, ...b]); //set {1,2,3,4}
c.set結構實現交集,原理是利用了set實例的has方法
let s2 = new Set([...a].filter(x => b.has(x)))//set {2,3}
d.set結構實現差集,同理利用了has方法
let s3 = new Set([...a].filter(x => !b.has(x)))//set {1}
你的直覺是否是這裏應該是{1,4},這裏的差集實際上是a裏面有且b裏面沒有的元素,而不是ab互相沒有。
2、WeakSet結構
WeakSet數據結構與Set相似,也不接受重複的值,但也有三點不一樣,一是WeakSet解構的成員只能是對象,二是WeakSet中的對象都是弱引用,三是WeakSet沒法遍歷。
1.WeakSet成員只能是對象
let s = new WeakSet(); s.add([{a:1},{b:2}]); console.dir(s); s.add(1);//報錯 Invalid value used in weak set
建立WeakSet 結構可經過new命令完成,WeakSet 接受任何含有Iterable接口的對象做爲參數。能夠看到當咱們add非對象元素,該操做報錯,可是add添加對象沒問題。
那麼咱們看這段代碼,爲何報錯了:
let s = new WeakSet([1,2,3]);
我在前面你說了,WeakSet的每一個成員必須是對象,前面咱們使用的是add方法,每次添加都是一個成員,這是直接使用new初始化,雖然傳遞的參數是數組,但本質上等同於:
let s = new WeakSet(); s.add(1).add(2).add(3);
因此咱們須要保證數組中的每一個元素也是對象,這樣就不會報錯了:
let s = new WeakSet([{a:1},{b:2}]);
其次能夠看到WeakSet方法並很少,add,has,delete三個,用法和set相同,這裏就不重複介紹了。
2.WeakSet結構成員均爲弱引用
咱們都知道,當一個對象不被任何地方引用,垃圾回收機制就會釋放掉這個對象所佔用內存。咱們在前面說WeakSet的成員都是對象,可是垃圾回收機制不考慮WeakSet的引用。
說直白點,如今對象a被A和WeakSet同時引用,A再也不引用了垃圾回收機制就直接釋放了,徹底無論WeakSet還在引用它。
也正是由於WeakSet成員是弱引用的緣由,咱們沒法保證何時成員就被釋放了,因此WeakSet沒有size屬性,也不可遍歷。
3、map數據結構
1.基本用法與增刪改查方法
傳統意義上的對象都是鍵值對組成的集合,鍵爲字符串,值爲一個對象,咱們是沒法使用對象做爲鍵的。
但Map打破了這個規則,咱們能夠經過Map建立鍵值都是對象的數據結構,這樣鍵再也不是做爲保存值的存在,在遍歷時,鍵值均可以是有效的對象。
let m = new Map(); console.dir(m);
從上圖中,能夠看到百分之80的方法與Set數據結構徹底相同,只是多了一個set方法和get方法。
set(key,value)方法:按照key/value添加成員,返回Map結構,支持鏈式寫法;若是key已存在,則覆蓋。
get(key)方法:按照key查找返回對應的value,若是未找到,返回undefined。
has(key)方法:查找是否包含某個key,返回一個布爾值。
delete(key)方法:刪除對應的key,返回一個布爾值,表示是否成功刪除。
clear()方法:清空整個Map數據結構。
let m = new Map(); let o = {name:'echo'}; m.set(o,{age:26}); m.get(o);//{age:26} m.has(o);//true m.delete(o);//true m.has(o);//false
那麼在上述代碼中,咱們爲map數據結構添加了一個key爲{name:'echo'}值爲{age:26}的成員。
同時咱們能夠經過get指定的key訪問到對應的value,delete仍是同樣返回是否刪除成功,has依舊是判斷該數據結構是否含有此成員。
添加成員固然不要求經過set,在new命令執行時,咱們能夠以一個數組的形式傳遞須要添加的成員。
let m = new Map([ ['name', '聽風是風'], ['age', 26] ]); m.has('name') //true m.get('name') //聽風是風 m.has('age') //true m.get('age') //26
其實初次看到這我是有點懵逼的,爲何我一個數組成員的兩個元素,成了Map數據結構中一個成員的key與value。其實這個不難理解,它等同於如下的執行:
let arr = [ ['name', '聽風是風'], ['age', 26] ]; let m = new Map(); arr.forEach(([key, value]) => m.set(key, value))
數組每一個元素又是一個雙元素數組,前者做爲map的key,後者做爲map的value
須要注意的是,map數據結構一樣不接受重複的值做爲成員,這裏的重複是指key名相同,若是相同,後者會覆蓋前者:
const m = new Map([ ['name', 1], ['name', 2] ]); console.log(m);//key:name value:2
除此以外,當咱們map的key是對象時,須要注意對象引用的問題:
let o = {name:1}; let m = new Map(); m.set(o,2) console.log(m.get(o));//2 m.set({name:1},2) console.log(m.get({name:1}));//undefined
在上述代碼中,若是咱們直接將{name:1}做爲key用於存值,在set執行時,沒法拿到對應的value,這是由於對象儘管寫法相同,但仍然是徹底不一樣的兩個東西;
因此在須要將對象作key時,請將此對象賦予一個變量,利用此變量做爲key進行存儲,在讀取時再次讀取這個變量,就能夠避免這個問題了。
其實說到這裏,關於map的key,實際上是跟內存地址相關。若是key是一個簡單數據類型,那麼只要兩個key徹底相等,就視爲一個key,且後者覆蓋前者,若是不相等,則反之。
若是key是一個對象,想正確的存取,請將對象賦予給一個變量再作set操做。不然會由於引用地址問題沒法訪問到你已經添加的key。
2.Map數據結構的遍歷方法
keys()方法:遍歷並返回鍵名
let m = new Map([ ['name', '聽風是風'], ['age', 26] ]); for(let key of m.keys()){ console.log(key);//name age };
values()方法:遍歷並返回鍵值
for(let value of m.values()){ console.log(value);//聽風是風 26 };
entries()方法:遍歷返回全部成員,注意,我沒說這裏是返回鍵值對
for(let item of m.entries()){ console.log(item); };
如上圖,返回兩個數組,每一個數組分別包含了key和value,因此若是咱們想直接訪問key,value,應該這麼寫:
for(let [key,value] of m.entries()){ console.log(key,value);//name 聽風是風,age 26 };
還記得在介紹Set數據結構是,咱們說Set的默認遍歷器接口等於values方法,因此咱們能夠簡寫遍歷,比較好運的是,Map數據結構的默認遍歷器接口等於entries方法,因此咱們還能夠繼續簡寫:
m[Symbol.iterator] === m.entries; //true for (let [key, value] of m) { console.log(key, value);//name 聽風是風,age 26 };
forEach方法,經過回調參數也能夠方便的訪問到Map結構的key與value
m.forEach((value, key, m) => console.log(value, key));//聽風是風 name,26 "age"
4、WeakMap數據結構
WeakMap與Map結構相似,但也有兩點不一樣,一是WeakMap成員的key只接受對象:
let m = new WeakMap(); m.set('name',1);//報錯
二是WeakMap的鍵名所引用對象爲弱引用,也就是不計入垃圾回收機制,這點與WeakSet一致。
let m = new WeakMap(); let ele = document.querySelector("#div"); m.set(ele, '這是一個div元素'); m.get(ele); //這是一個div元素
在上述代碼中,咱們先是將獲取的dom存在了ele變量中,此時對於div dom的引用次數是1次。
而後咱們又將ele做爲key,爲這個ele添加了一些說明,照理說,div dom此時又被WeakMap結構引用,因此div引用次數是2次。
但因爲WeakMap的key名對象是弱引用,因此這裏div一共的引用此事仍是1次。當咱們讓ele再也不引用div元素時,垃圾回收機制不會考慮WeakMap對於div的引用,而是直接釋放,這點其實與WeakSet是保持一致的。
強調一點的是,WeakMap弱引用的是key,而不是value,這裏有個例子:
let m = new WeakMap(); let key = {}; let value = {a: 1}; m.set(key, value); value = null; m.get(key) //{a:1}
即使咱們將WeakMap中value所引用的對象釋放,其實垃圾回收機制仍是將WeakMap的引用計爲1次,因此還能正常讀取到。
由於key是弱引用的緣故,因此與WeakSet同樣,不存在遍歷方法。
WeakMap結構最大的一個用處就是用於保存dom,這樣dom元素被刪除也不會形成內存泄漏問題:
let ele = document.getElementById('logo'); let fn = function () { console.log(1) }; let m = new WeakMap(); //將dom元素與須要執行的函數做爲WeakMap結構的key與value m.set(ele, fn); //爲dom元素增長監聽 ele.addEventListener('click', function () { //執行監聽函數 m.get(ele)(); }, false);
關於WeakMap這裏就很少作介紹了,至少我目前開發基本使用不到.....
不僅是是WeakMap,Set與Map的使用機率基本很低,這裏就純作一個整理了,往後萬一用到,或者說使用逐漸普及,也方便查找。
那麼就寫到這裏了。