Sets 和數組同樣,都是一些有序值的的集合,可是Sets 和數組又有所不一樣,首先Sets 集合中不能存有相同的值,若是你向Sets 添加劇復的值,它會忽略掉, 其次Sets 集合的做用也有所不一樣,它的主要做用一是存儲數據,二是在於看一個值是否是在集合中,而不是對單個值進行操做,Sets 的查找更快。那怎樣才能建立一個Sets, 使用new Set(); 怎樣才能添加值呢? 調用add() 方法json
let set = new Set(); set.add(1); set.add(2); set.add({ name: 'sam' })
剛纔咱們說了,Sets 集合中不能添加劇復的值,若是添加了,Sets 也會把它忽略掉,如今就能夠試一試了,添加一個1,數組
let set = new Set(); set.add(1); set.add(2); set.add({ name: 'sam' }) set.add(1)
那咱們怎麼才能知道有沒有添加到set中呢? 它又一個size屬性,能夠返回集合中又多少個元素, app
console.log(set.size) // 3
set 中只要3個元素, 代表沒有添加成功, 直接console.log(set), 也能看出它裏面的包含的值。那這又引出了例外一個問題,Sets 集合是怎麼判斷兩個值是重複或相等呢?內部調用的是Object.is() 方法判斷相等性。dom
除了調用add() 方法添加數據外,咱們也能夠建立Sets 的時候,直接進行初始化。new Set() 可接受數組做爲參數,若是數組中有重複的值,初始化的時候直接過濾掉。函數
let set = new Set([1, 1, 2, 3, 3]); console.log(set.size) // 3
添加數據以後,能不能刪除呢? 固然能夠了,調用 delete() 方法能夠刪除一個元素,調用clear() 方法直接清空集合。this
let set = new Set([1, 1, 2, 3, 3]); console.log(set.size) // 3 set.delete(1); // 刪除集合中的元素1 console.log(set.size); // 2 set.clear(); // 清空集合 console.log(set.size); // 0
還有一個has 方法,就是判斷一個元素是否是在集合中spa
let set = new Set([1, 1, 2, 3, 3]); set.has(1); // true set.has(6); // false
剛纔咱們說了,可使用console.log 來查看集合的內容,其實還有更好的辦法,就是forEach 方法,對集合進行迭代。forEach 方法和數組的forEach 用法一致,都是接受一個函數,函數有三個參數,不過這三個參數和數組的不一樣,由於Sets 集合中並無index, 對於Sets 集合的迭代來講,第一個是value, 第二個值也是value, 第三個是集合自己,你可能會問,第一個和第二個參數的值一致,爲何還要設置這個參數, 這是由於保持forEach API 的用法一致,若是Sets 的forEach 單獨兩個參數,那很容易忘掉。prototype
let set = new Set([1, 1, 2, 3, 3]); set.forEach(function(value, key, ownerSet) { console.log(value, key); console.log(value === key); console.log(ownerSet === set) })
既然可使用數組對Sets集合進行初始化,那麼Sets集合能不能轉化成數組呢?也能夠,使用... 分割符。code
let set = new Set([1, 1, 2, 3, 3]); let arr = [...set]; console.log(arr); // [1, 2, 3]
這時能夠發現對數組進行了去重,簡單的數組去重,用Sets 集合就能夠解決了。對象
以上咱們建立的set 稱爲強set(Strong set), 爲何呢? 主要是由於當set 存儲對象的時候,它存儲的是對象的引用,只要set 存在,它裏面引用的對象也會存在,對象就不會被垃圾回收,即便set 外面 這個對象的全部引用都消失了。
let set = new Set(); let obj = {}; set.add(obj); console.log(set.size); // 1
如今set 建立成功了, 而且存儲了一個對象的引用obj. 那如今讓對象的引用消失,obj =null; 你會發現set 中仍然存在着對象的引用,由於set.size 爲1;
obj = null; console.log(set.size); // 1
咱們能夠把set 轉化成數組,看到裏面有一個對象
console.log([...set])
但有時候,咱們並不想這麼作,尤爲是操做dom的時候。若是set 集合中存儲的是一個DOM 對象的引用,當咱們把這個dom元素刪除掉,這個元素的引用 其實就沒有做用了,set 中再保留這個 dom 對象的引用也就沒有意義了。 簡單的dom結構
<div id="app"> <button type="button" class="btn">5+6的結果</button> </div>
建立set實例,保存這個dom 的引用
let set = new Set(); let btn = document.getElementsByClassName('btn')[0]; set.add(btn);
而後刪除這個btn 元素
document.getElementById('app').removeChild(btn);
這時候,你會發現頁面中沒有這個元素了,可是btn 和 set 集合中仍然保留這個btn 元素的引用。
console.log(btn);
console.log(set.size); // 1
btn 好辦,直接設置爲null 就行了。可是set 中的元素就很差辦了,這時ES6 提供了weak set, 專門處理這種引用的問題,若是 set 中引用的對象,就剩下在set 中的引用了,那麼set 中的引用就會消失,對象也就能夠垃圾回收了。
建立weak set 使用的weakSet 函數,而且它裏面只存對象,add, delete, has 方法和 set 使用一致,
let weakSet = new WeakSet(); let obj = {}; weakSet.add(obj); weakSet.has(obj); weakSet.delete(obj);
和set 最大的不一樣就是咱們上面剛說的,若是 obj = null, 就只剩下weakset 中存在對象的引用,那麼這個引用也會消失,可是沒有更好的判判斷方法。
obj = null;
執行obj = null; 後,咱們就能夠判斷weakSet 中,沒有對象的引用了。除了這個不一樣外, weakset, 不能迭代,沒有size 和forEach 方法,它只能存儲對象。
Map
Map和對象同樣,都是鍵值對的方式存儲數據,可是你想,有對象了,還要map 作什麼? map 更強大,由於對象的全部key 都是字符串,你即便添加的時候不是字符串,對象也會 key 轉化爲字符串。
let obj = {}; let num = 5; let string = '5' obj[num] = '5 string'; obj[string] = '5 number'; console.log(obj); // {'5' : '5 number'}
咱們給對象添加了兩個屬性,一個是數字5, 一個是字符串‘5’, 但到最後發現對象中只有一個字符串5. 由於當咱們給對象添加數字5的時候,它先轉化爲字符串‘5’, 發現對象中已經有字符串5 的屬性了,就變成了改變對象的屬性值了。 map 就不同了,鍵和值能夠是任意類型。建立map 使用的是new Map, 添加屬性使用的是set 方法,set 也簡單, 有倆個參數,第一個是key, 第二個是value.
let map = new Map(); map.set(5, '5 number'); map.set('5', '5 string'); console.log(map); // Map { 5 => '5 number', '5' => '5 string' }
當咱們向map 中增長key/value的時候,它是怎麼判斷這個key是否是存在map 中呢? 使用的是Object.is() 方法來進行判斷,沒有進行類型轉化,因此 key 能夠是任意值了。給map 添加值之後,怎麼獲取呢?使用get 方法,一個參數key
console.log(map.get(5)); // '5 number'
除了這兩個方法方法外,它還要has, delete, clear 方法,同時有一個 size 屬性。 has 接受一個參數key, 判斷存不存在,delete 接受一個參數key, 刪除這個key, clear 不接受參數,直接清空map. size 以上返回有多少數據。
let map = new Map(); map.set(5, '5 number'); map.set('5', '5 string'); console.log(map.has(5)); // true console.log(map.size); // 2 map.delete(5); console.log(map.has(5)); // false console.log(map.size); // 1 map.clear(); console.log(map.size) // 0
Map 也可使用數組進行初始化,不過,數組要用二維數組,由於map 中的每一項都是key/value, 數組中的每一項也應該有兩個值,兩個值只能用再用一個數組進行表示了,數組的第一項是key, 第二項是value。
let map = new Map([['name', 'json'], ['age', 30]]);
你可想到key/value 不該該是對象嗎,數組中的每一項是對象纔對,但咱們也說了,對象的key 只能是字符串,因此不能徹底表示map,由於map 的key 是任意值,數組正好,數組中的每一項都是任意值,只不過語法比較奇怪, 數組的第一項是key, 第二項是value.
獲取到map 後,可使用forEach 進行迭代,用法也會數組一致。
let map = new Map([['name', 'json'], ['age', 30]]); map.forEach((value, key, ownerMap) => { console.log(value, key); console.log(map === ownerMap) })
和WeakSet 同樣,map 也提供了WeakMap, WeakMap 的key 是必須是對象,若是 key引用的一個對象,只剩下在weakMap的key 中引用,其餘的對這個對象的引用都不存在了,weakMap 中的key以及它對應的value就會自動刪除。weak map 的建立是new WeakMap(); 它有set get, has, delete 方法,但沒有size, clear(), forEach 等。
let map = new Map(); let btn = document.getElementsByClassName('btn')[0]; map.set(btn, 'btn'); map.get(btn); map.has(btn); map.delete(btn); btn = null; // map 中的key btn 以及它的value 會自動刪除
weak map 還要一個做用,能夠創造對象的私有屬性, 當我建立對象的時候,一般寫一個構造函數
function Person(name) { this. name = name; } Person.prototype.getName = function() { return this.name; }
但這時,建立一個Person 對象的時候,咱們能夠直接訪問name 屬性,
const person = new Person('sam'); console.log(person.name) // sam
可是咱們不想讓用戶直接訪問name 屬性, 直接使用下面的方法
let Person = (function(){ let privateData = new WeakMap(); function Person(name) { privateData.set(this, {name: name}) } Person.prototype.getName = function() { return privateData.get(this).name; } return Person; })() let person = new Person('json'); console.log(person.getName()) // josn