温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ES6中Set与WeakSet集合实例分析

发布时间:2022-03-31 16:12:17 来源:亿速云 阅读:143 作者:iii 栏目:编程语言

这篇文章主要讲解了“ES6中Set与WeakSet集合实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ES6中Set与WeakSet集合实例分析”吧!

    Set是值永不重复的特殊集合

    每天都用数组,有没有过一个Moment,担心插入了重复的值?使用Set集合吧!Set拥有特殊的数据结构,保证插入的值永远不会重复。

    Set集合基础API

    通过Set.prototype.constructor 构造函数创建Set实例

    /*
     * 仅实例化:调用构造函数,不传参数
     */ 
    let empty_set = new Set()    
    
    
    /*
     * 实例化同时初始化:传入任意iterate对象,将其转换成Set集合
     */ 
    let transfer_set4arr = new Set([1, 2, 3])
    // 返回Set(3) {1, 2, 3}
    
    let transfer_set4string = new Set("huilin")
    // 返回Set(5) {"h", "u", "i", "l", "n"}
    
    let transfer_set4set = new Set(new Set([5, 6]))
    // 返回Set(2) { 5, 6 }

    访问 Set.prototype.size属性,返回集合中元素的个数

    console.log(empty_set.size) // 0
    console.log(transfer_set4arr.size)  // 3

    调用 Set.prototype.has(value) 方法,判断元素是否存在

    // 相比起Array.includes(),Set.has()性能更高,因为专门对成员测试进行了优化
    console.log(empty_set.has(1))   // false
    console.log(transfer_set4arr.has("h")) // true

    关于唯一值的判断

    • Set集合为确保值的唯一性,使用Object.is(value1,value2)进行判断,而不是通过===(恒等符号)符号来判断的,因为恒等判断会将两边的变量进行强制类型转换。

    • 比如,两个变量的值均为NaN,或者0和-0,用JS判断是不相等的,但Object.is()认为是同一个只,因此不能存入Set集合中。

    想了解更多关于Object.is(),请跳转查看:developer.mozilla.org/zh-CN/docs/…

    let n1 = NaN
    let n2 = NaN
    
    console.log(n1 === n2)  
    // 恒等符号判断两者不一致,输出false
    
    console.log(Object.is(n1,n2)) 
    // 但Object.is()判断两者是相同的,输出false
    
    // Set集合不允许将两个NaN放入集合
    let set = new Set()
    set.add(n1).add(n2)
    console.log(set.size)   
    // size: 1

    而面对复杂数据类型时,主要通过对象的引用进行判断。引用不一致,即便数据结构一致,也认为只不相同,因此能存入Set集合。

    let same_value_set = new Set();
    // 先存入一个对象
    same_value_set.add({num: 0});
    // 再存入一个结构一致的新对象
    let obj = {num: 0};
    same_value_set.add(obj);
    // 都能存入成功
    console.log(same_value_set.size); // 2

    调用Set.prototype.add(value) 方法,向集合追加数据

    // add()方法可以追加任意类型的数据,不论是原始值或者是对象引用
    
    let set1 = new Set()
    // 由于add()方法始终返回当前实例的引用,所以进行链式调用
    set1.add(1).add(2).add(3)
    console.log(set1) // Set(3) {1, 2, 3}
    
    // 注意:当add()传入数组时,Set会将数组实例插入集合,而不是数组内的元素
    set1.add([4, 5])
    console.log(set1) // Set(4) {1, 2, 3, [4, 5]}

    调用Set.prototype.delete(value) 方法,移除集合中的元素

    // delete()方法返回移除操作是否成功,与.has()方法一样
    let success = set1.delete(1)
    console.log(success)
    // true

    调用Set.prototype.clear() 方法,清空集合

    let num_set = new Set([1, 6, 3])
    console.log(num_set)
    // Set(3) { 1, 6, 3 }
    
    set1.clear()
    console.log(num_set)
    // Set(0) {}

    Set集合遍历的3种方式

    由于集合没有下标/索引,通常被认为是“无序集合”。但JavaScript会记住元素插入的顺序,所以遍历的时候也按顺序对元素进行迭代。

    直接遍历Set集合

    let set = new Set([1, 2, 3, 4, 5])
    for(let item of set){
        console.log(item)
    }
    // 依次输出:1 2 3 4 5

    创建迭代器进行遍历

    /*
     * 创建迭代器的有三种方式
     * Set.prototype.entries()
     * Set.prototype.keys()
     * Set.prototype.values()
     */ 
    
    // Set集合只有value而没有key,但为了使得和遍历Map对象相似,Set.entries()创建新的Iterator对象时,每一项的键和值都相等,即[value,value]
    for(let [key,value] of set.entries()){
        console.log(value)
    }
    // 依次输出:1 2 3 4 5
    
    // Set.keys()创建新的Iterator对象,返回每一项值
    for(let key of set.keys()){
        console.log(key)
    }
    // 依次输出:1 2 3 4 5
    
    // Set.values()和Set.keys()一致,返回每一项的值
    for(let value of set.values()){
        console.log(value)
    }
    // 依次输出:1 2 3 4 5

    调用Set.prototype.forEach(callbackFn)方法遍历

    // forEach(callbackFn) 按照插入顺序调用callbackFn,取出每项值
    set.forEach(item => {
        console.log(item)
    })
    // 依次输出:1 2 3 4 5

    Set集合案例实践

    Set集合与Array数组之间的转换

    /*
     * Set转Array
     */
    let set1 = new Set([1, 2, 3])
    // Array.from()方法
    let arr1 = Array.from(set1)  
    // 扩展运算符
    let arr2 = [...set1]  
    
    /*
     * Array转Set
     */
     // 利用Set构造函数
    let set = new Set(array)

    单个数组去重

    let set = new Set([1, 2, 4, 4, 2, 5])
    console.log(set)
    // Set(4) { 1, 2, 4, 5 }

    多个数组合并去重

    let arr1 = [1, 2, 4]
    let arr2 = [1, 5, 6]
    
    // 利用Set集合的特性,集合内的元素都是唯一的
    let result = new Set([...set1, ...set2]) 
    console.log(result)
    // Set(5) { 1, 2, 4, 5, 6 }

    获取交集(重复的元素)

    let set1 = new Set([1, 2, 4])
    let set2 = new Set([1, 5, 6])
    
    // 返回set1和set2都存在的元素
    let result = new Set([...set1].filter(x => set2.has(x))) 
    console.log(result)
    // Set(1) { 1 }

    判断是否有交集(重复的元素)

    let set1 = new Set([1, 2, 4])
    let set2 = new Set([1, 5, 6])
    
    function isMixed(set, subset) {
        for (let elem of subset) {
            if (set.has(elem)) {
                return true;
            }
        }
        return false;
    }
    
    console.log(isMixed(set1, set2))
    // true

    获取差集:只返回重复

    let set1 = new Set([1, 2, 4])
    let set2 = new Set([1, 5, 6])
    
    function difference(setA, setB) {
        let result = new Set()
        for (let elem of setB) {
            if(setA.has(elem)){
                result.add(elem)
            }
        }
        return result;
    }
    
    console.log(difference(set1, set2))

    WeakSet“弱”在哪里?

    除了Set集合外,ES6还提供了WeakSet和WeakMap。既然集合的名字都叫“Weak(弱)的集合”了,究竟它“弱”在哪里呢?

    弱功能

    WeakSet不允许插入原始值,仅支持对象的引用;

    let val1 = {id: 1},
        val2 = {id: 2}
    
    let ws = new WeakSet()
    
    // 和Set集合一样,WeakSet的值也不重复,同时add()也返回集合实例,所以可以链式操作
    ws.add(val1).add(val1).add(val2)
    
    // 不允许插入基础数据类型
    ws.add(3)
    // 报错:TypeError:Invalid value used in WeakSet
    
    // 但可以先包装成对象后再插入
    let val3 = new Number(3)
    ws.add(val3)
    console.log(ws.has(val3))
    // 输出:true
    • WeakSet仅实现了add()、has()、delete()三个操作方法;

    • WeakSet不允许遍历,也没有size或者length属性;

    弱引用

    要说弱引用,先看看什么是强引用:

    // 声明一个对象
    let handsome = {
        name: "huilin",
        age: 30
    }
    
    // 放入数组
    let arr = [1, handsome, 2]
    console.log("release before arr length", arr.length) // 3
    
    // 放入Map
    let user = {
        oid: 10001,
        classify: "Chinese",
        staffReference: handsome
    }
    console.log("release before map length", Object.keys(user).length) // 3
    
    console.log("----")
    
    // 突然把对象置为null
    handsome = null
    // 强引用的容器中,对象仍然存在没有被回收
    console.log("release after arr length", arr.length) // 3
    console.log(arr[1]) // { name: "huilin", age: 30 }
    console.log("release after map length", Object.keys(user).length) // 3
    console.log(user.staffReference) // { name: "huilin", age: 30 }

    从测试代码看出,除非容器销毁,否则引用的对象一直没有被回收。而所谓弱引用,就是希望容器是根据元素自动伸缩的,一旦对象为null,容器中的引用也跟着回收。

    let obj1 = {
        name: "huilin",
        age: 30
    }
    
    let obj2 = {
        name: "cc",
        age: 29
    }
    
    let ws1 = new WeakSet()
    ws1.add(obj1).add(obj2)
    console.log(ws1.has(obj1))  // true
    
    // 不管是从容器操作元素
    ws1.delete(obj1)
    console.log(ws1.has(obj1))  // false
    
    // 或者是对象自己置为null,都会自动回收
    obj2 = null
    console.log(ws1.has(obj2))  // false

    感谢各位的阅读,以上就是“ES6中Set与WeakSet集合实例分析”的内容了,经过本文的学习后,相信大家对ES6中Set与WeakSet集合实例分析这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI