ES6 新增集合----- Set 和Map

  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
相關文章
相關標籤/搜索