es6-Set與Map

謝鳶發表於2019-02-16

se5中的set與map

在est5中開發者使用物件屬性來模擬。set多用於檢查鍵的存在,map多用於提取資料。

{
    let set = Object.create(null)
    set.foo = true;
    //檢查屬性是否存在
    if (set.foo) {
        //其他操作
    }

    let map = Object.create(null);
    map.foo = `一個值`;
    let val = map.foo;

    console.log(`map-->:`, val); //map-->:一個值`
}

在簡單情況下將物件作為map和set來使用都是可行的,但是一旦接觸到物件屬性的侷限性,此方式就會遇到更多的麻煩。

{
    let map1 = Object.create(null),
        key1 = {},
        key2 = {};

    map1[key1] = `foo`;
    console.log(`key2-->:`, map1[key2]);

    let map2 = Object.create(null);
    map2.count = 1;
    //是想檢查count的存在,還是非零值?
    if (map2.count) {
        //...
    }
}

map1[key1]和map1[key2]引用了同一個值。由於物件屬性只能是string,又因為物件預設的string表達形式是`[object object]`。導致key1和key2被轉換為同一個字串。map2中count的用法存在歧義。該if語句內的程式碼都會被執行因為1被隱式轉換為true。然而count的值為0則會被隱式轉為false。在大型應用中這類問題都是難以確認,難以除錯的。這也是新增set和map型別的原因。set型別是一種無重複值的有序列表。set允許對它包含的數進行快速訪問,從而更有效的追蹤各種離散值。

建立set型別

使用new set()來建立。呼叫add()方法向集合中新增元素,訪問集合的size屬性獲取集合數量。

{
    let set = new Set();

    set.add(5);
    set.add(`5`);
    console.log(`typeof set-->:`, typeof set)
    console.log(`set-->:`, set)
    console.log(`size-->:`, set.size)
}

set不會使用強制型別轉換來判斷值是否重複,這意味著set可以同時包含number(5)和string(5),唯一的例外-0和+0在set中被判定是相等的,如果向set集合中新增多個物件,則他們之間彼此獨立。

{
    let set = new Set();
    let key1 = {};
    let key2 = {};

    set.add(key1);
    set.add(key2);
    console.log(`typeof setobject-->:`, typeof set)
    console.log(`setobject-->:`, set)
    console.log(`size-->:`, set.size)
}

由於key1和key2不會被轉換為字串,所以在set內部是不同的項,如果他們被轉化為字串,那麼都會等於”[object object]”,如果多次呼叫add()並傳入相同的值作為引數。那麼後續的呼叫會被忽略。

{
    let set = new Set();

    set.add(5);
    set.add(`5`);
    set.add(5);
    console.log(`typeof set-->:`, typeof set)
    console.log(`set-->:`, set)
    console.log(`size-->:`, set.size)
}

第二次重複傳入numner(5)並不會被新增到set集合中,那麼size的屬性值還是為2。也可以使用陣列來初始化set集合。集合同樣會過濾重複的值。

{
    let set = new Set([1, 2, 3, 4, 5, 5, 5, 5, 5, 5]);
    console.log(`size-->:`, set.size);
}

通過has()可以檢測set集合中是否存在某個值。

{
    let set = new Set();

    set.add(5);
    set.add(`6`);
    console.log(`set has-->:`, set.has(6));
    console.log(`set has-->:`, set.has(`6`))
    console.log(`set has-->:`, set.has(5))
    console.log(`set has-->:`, set.has(`5`))
}

set集合中相同的number和sting並不會返回true。呼叫delete()方法可以移除set中的某一個值,呼叫clear()方法可以移除所有值。

{
    let set = new Set();

    set.add(5);
    set.add(`6`);
    console.log(`set has-->:`, set.has(`6`));
    set.delete(`6`)
    console.log(`set has-->:`, set.has(`6`))
    console.log(`size-->:`, set.size)
    set.clear();
    console.log(`size-->:`, set.size)
}

set集合簡單易用,可以有效的跟蹤多個獨立有序的值。

set的forEach

set集合和陣列的forEach類似,執行機制也比較類似。forEach()方法的回撥接收3個引數:
1.集合中索引的位置。
2.被遍歷引數的值
3.集合本身

{
    let set = new Set([`a`, `b`, `c`, `d`, `e`]);
    set.forEach((k, val, owner) => {
        console.log(`set-forEach-k-->:`, k);
        console.log(`set-forEach-val-->:`, val);
        console.log(`set-forEach-owner-->:`, owner);
    })
}

將set轉換為陣列

將陣列轉換為set集合的過程很簡單,需要給set集合傳入陣列即可。將集合轉回陣列,只需要使用展開運算子即可。

{
    let arr = [1, 2, 3, 4, 5, 5, 5, 5, 5, 5];
    let set = new Set(arr);
    let newArr = [...set];
    //ps: 程式碼行數太多可以壓縮下
    let newArr2 = [...new Set([1, 2, 3, 4, 5, 5, 5, 5, 5, 5])];
    console.log(newArr, newArr2)
}

建立map型別

map型別是鍵值對的有序列表,鍵和值都可以是任意型別,可以呼叫set()方法傳遞一個鍵和一個關聯的值,來給馬屁新增項;此後使用鍵名來呼叫get()方法獲取對應的值。

{
    let map = new Map();
    map.set(`title`, `es6`);
    map.set(`year`, 2016);

    console.log(`map-title-->`, map.get(`title`))
    console.log(`map-year-->`, map.get(`year`))
}

map的方法

map和set共享了幾個方法。以下的方法和屬性map和set上都存在:
1.forEach(val, k, owner): 遍歷map
2.has(key):判斷指定的鍵值是否存在
3.delete(key):移除map中鍵以及對應的值
4.clear():移除map中所有的鍵和值
5.size:指明包含多個鍵值對。

{
    let map = new Map();
    map.set(`title`, `es6`);
    map.set(`year`, 2016);

    map.forEach((val, k, owner) => {
        console.log(`map-forEach-k-->:`, k);
        console.log(`map-forEach-val-->:`, val);
        console.log(`map-forEach-owner-->:`, owner);
    })
    console.log(`map-size-->:`, map.size);

    console.log(`map-has-->:`, map.has(`title`));

    map.delete(`title`);
    console.log(`map-->:`, map);

    map.clear();
    console.log(`map-->:`, map);
}

小結

es6正式將set與map引入。在此之前往往使用物件來模擬,但是由於與物件屬性有關的限制,這麼做會經常遇到問題。
這裡並沒有弱引用weakset和weakmap,有這方面需要的可以自己去查閱