JavaScript Set物件

雲崖先生發表於2020-07-29

JavaScript Set物件

Set

  用於儲存任何型別的唯一值,無論是基本型別還是引用型別。

 

  只有值沒有鍵

  嚴格型別檢測儲存,字串數字不等同於數值型數字

  儲存的值具有唯一性

  遍歷順序是新增的順序,方便儲存回撥函式

 

  其實Set型別更多的是運算元據,而並非儲存。

 

基礎知識

宣告定義


  以下示例演示出如何使用Set型別儲存資料。

 

<script>"use strict";
​
        let set = new Set([1, "1", 1, 1, 1, 2, 3, 4, 5, "2"])  // 嚴格型別檢測 1 != "1"
​
        console.log(set instanceof Set);  // true
​
        console.log(set);  // set(7) {1, "1", 2, 3, 4, 5, "2"}
</script>

 

新增元素


  以下示例將演示如何將任意值元素新增進set容器中,使用add()方法進行新增元素的操作。

 

<script>"use strict";
​
        let set = new Set()
​
        set.add(1);
​
        set.add(["一","二","三"]);
​
        set.add('1');
​
        console.log(set); // Set(3) {1, Array(3), "1"}
        
</script>

 

獲取數量


  使用size屬性獲取set容器中的元素個數。

 

<script>"use strict";
​
        let set = new Set()
​
        set.add(1);
​
        set.add(["一","二","三"]);
​
        set.add('1');
​
        console.log(set); // Set(3) {1, Array(3), "1"}
​
        console.log(set.size);  // 3
</script>
 

 

元素檢測


  使用has()方法檢測元素是否存在。

 

<script>"use strict";
​
        let set = new Set()
​
        set.add(1);
​
        set.add(["一", "二", "三"]);
​
        set.add('1');
​
        console.log(set); // Set(3) {1, Array(3), "1"}
​
        console.log(set.has(["一", "二", "三"]));  // 由於是不同的引用地址,故結果為 false
        
        let array = ["四", "五", "六"];
​
        set.add(array)
​
        console.log(set.has(array));  // 現在的引用地址一致,結果為 true
</script>

 

刪除元素


  使用delete()方法刪除單個元素,返回值為boolean型別。

 

<script>"use strict";
​
        let set = new Set()
​
        set.add(1);
​
        set.add(["一", "二", "三"]);
​
        set.add('1');
​
        console.log(set); // Set(3) {1, Array(3), "1"}
 
        let res = set.delete(1); // 值型別,可以直接刪除
​
        console.log(res); // true 代表刪除成功
​
        res = set.delete(["一", "二", "三"])  // 引用型別,不可以直接刪除
​
        console.log(res); // false 代表刪除失敗
</script>

 

清空容器


  使用clear()方法可使set容器清空。

 

<script>"use strict";
​
        let set = new Set()
​
        set.add(1);
​
        set.add(["一", "二", "三"]);
​
        set.add('1');
​
        set.clear();
​
        console.log(set.size);  // 0
</script>

 

陣列轉換


  轉換資料型別是為了更好的操縱資料,可以使用...語法或者Array.form()方法將set轉換為array

  我們可以充分的結果set去重的特性,以及array豐富的操作方法來任意操縱我們的元素。

 

  如下,我們將set型別轉換為了陣列。

<script>"use strict";
​
        let set = new Set(["雲崖先生", "男", 18])
​
        let array = [...set];
​
        console.log(array);  // (3) ["雲崖先生", "男", 18]
​
        console.log(array instanceof Array); // true
</script>

 

  將陣列轉換為set,可以充分利用去重特性。

<script>"use strict";
​
        let array = new Array(1, 1, 1, 2, 2, 3, 4, 5);
​
        array = new Set(array);  // 去重
​
        array = Array.from(array)
​
        console.log(array instanceof Array); // true
​
        console.log(array); // (5) [1, 2, 3, 4, 5]
</script>

 

遍歷操作

 

迭代器建立


  使用 keys()/values()/entries() 都可以返回迭代物件,因為set型別只有值所以 keysvalues 方法結果一致。

 

<script>

        "use strict";

        let set = new Set(["一", "二", "三", "四", "五"]);

        let iter_keys = set.keys();

        let iter_values = set.values();

        let iter_entries = set.entries();

        console.log(iter_keys);

        console.log(iter_values);

        console.log(iter_entries);
        
</script>

 

image-20200729172338715

 

forEach


  使用forEach來迴圈set容器。

 

<script>

        "use strict";

        let set = new Set(["一", "二", "三", "四", "五"]);


        set.forEach(function (index, value) {
                console.log(index, value);
        });


</script>

 

image-20200729172549381

 

for/of


  也可使用for/of進行迴圈。

 

<script>

        "use strict";

        let set = new Set(["一", "二", "三", "四", "五"]);


        for (let i of set) {
                
                console.log(i);
        }

</script>

 

image-20200729172734276

 

多集合操作

交集


  交集代表set1set2共有的部分。

 

<script>

        "use strict";

        let set1 = new Set(["一", "二", "三", "四", "五"]);
        let set2 = new Set(["三", "四", "五", "六", "七"]);

        let new_set = new Set(

                Array.from(set1).filter(function (value) { 
                        return set2.has(value) 

                        })
        );

        console.log(new_set);  // Set(3) {"三", "四", "五"}

</script>

 

差集


  差集代表一個集合有,另一個集合沒有的部分。

 

<script>

        "use strict";

        let set1 = new Set(["一", "二", "三", "四", "五"]);
        let set2 = new Set(["三", "四", "五", "六", "七"]);

        let new_set = new Set(

                Array.from(set1).filter(function (value) {
                        return !set2.has(value)

                })
        );

        console.log(new_set);  // Set(3) Set(2) {"一", "二"}

</script>

 

並集


  將兩個集合合併成一個集合,多餘的元素會被剔除,這就是並集。

 

<script>

        "use strict";

        let set1 = new Set(["一", "二", "三", "四", "五"]);
        let set2 = new Set(["三", "四", "五", "六", "七"]);

        let new_set = new Set([...set1,...set2]);

        console.log(new_set);  // Set(7) {"一", "二", "三", "四", "五", "六", "七"}

</script>

 

WeakSet

  WeakSet結構同樣不會儲存重複的值,它的成員必須只能是物件型別的值。

 

  • 垃圾回收不考慮WeakSet,即被WeakSet引用時引用計數器不加一,所以物件不被引用時不管WeakSet是否在使用都將刪除

  • 因為WeakSet 是弱引用,由於其他地方操作成員可能會不存在,所以不可以進行forEach( )遍歷等操作

  • 也是因為弱引用,WeakSet結構沒有keys()values()entries()等方法和size屬性

  • 因為是弱引用所以當外部引用刪除時,希望自動刪除資料時使用 Weakset

 

宣告定義


  WeakSet中只能儲存容器型別的物件,即引用型別,不能儲存值型別。

<script>

        "use strict";

        let array = [1,2,3];

        let dict = {"k1":"v1","k2":"v2"};

        let set = new WeakSet([array,dict]);  // 在 WeakSet中只能儲存容器型別的物件,即引用型別。不能儲存值型別

        console.log(set);

</script>

 

  儲存值型別會丟擲異常。

<script>

        "use strict";

        let array = [1,2,3];

        let dict = {"k1":"v1","k2":"v2"};

        let symbol = new Symbol();  // 值型別

        let set = new WeakSet([array,dict,symbol]);  // 在 WeakSet中只能儲存容器型別的物件,即引用型別。不能儲存值型別

        console.log(set); // Uncaught TypeError: Symbol is not a constructor

</script>

 

操作方法


 

方法說明
add() 新增一個引用型別物件
delete() 刪除一個引用型別物件
has() 判斷是否存在一個引用型別物件

 

垃圾回收


  對於標記清除法來說,存在於WeakSet中的物件並不會增加引用計數,因此也被稱之為弱引用。

  WeakSet中物件的外部引用計數為0後,垃圾回收機制將清理該物件,並且WeakSet容器內並不會儲存該物件。

 

<script>

        "use strict";

        let array = [1, 2, 3];

        let dict = { "k1": "v1", "k2": "v2" };

        let set = new WeakSet([array, dict]);

        console.log(set);  // array還在裡面

        array = null;  // 清理,引用計數為0

        setInterval(() => {

                console.log(set);  // array 不在了

        }, 3000);

</script>

 

image-20200729175844897

 

作用詳解


  根據WeakSet這個特性,我們可以用它來儲存一下經常存取的資料。

  當物件被刪除後,我們不用管WeakSet容器中是否含存有該資料。

 

  示例如下:

 

 

 

  將標籤節點全部放入集合中,當在點選的時候新增類並且移出集合設定透明度,當再次點選的時候又將標籤移入集合即可。

 

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_h1wr0ianmf5.css">
        <style>
                body {
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        flex-flow: column wrap;
                        height: 100vh;
                        width: 100vw;
                }


                input {
                        border: none;
                        height: 20px;


                }

                div {
                        border: 1px solid #ddd;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        margin-bottom: 10px;
                        padding: 0 5px;
                        width: 200px;
                        height: 30px;

                }

                div input {
                        flex: 1;
                }

                div input:focus {
                        outline: none;
                }


                div i {
                        background-color: rgba(0, 255, 96, 5);
                        padding: 2px;
                        border-radius: 10%;

                }

                i.iconfont {
                        font-size: 12px;
                }

                .hidden {
                        opacity: .5;
                }
        </style>
</head>


<body>
        <div>
                <input type="text"><i class="iconfont icon-shanchu"></i>
        </div>
        <div>
                <input type="text"><i class="iconfont icon-shanchu"></i>
        </div>
        <div>
                <input type="text"><i class="iconfont icon-shanchu"></i>
        </div>
        <div>
                <input type="text"><i class="iconfont icon-shanchu"></i>
        </div>


</body>
<script>

        "use strict";

        let divs = document.querySelectorAll("div");

        let set = new WeakSet([...divs]);

        divs.forEach(function (ele) {

                ele.childNodes[2].addEventListener("click", function (param) {
                        if (set.has(this.parentNode)) {
                                set.delete(this.parentNode);
                                this.parentNode.classList.add('hidden');
                        }
                        else {
                                set.add(this.parentNode);
                                this.parentNode.classList.remove("hidden");
                        }

                })
        })

</script>

</html>

 

相關文章