ES6中Set与WeakSet集合的深入讲解

目录
  • Set是值永不重复的特殊集合
  • Set集合基础API
    • 关于唯一值的判断
    • Set集合遍历的3种方式
  • Set集合案例实践
    • Set集合与Array数组之间的转换
    • 单个数组去重
    • 多个数组合并去重
    • 获取交集(重复的元素)
    • 判断是否有交集(重复的元素)
    • 获取差集:只返回重复
  • 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

Reference

总结

到此这篇关于ES6中Set与WeakSet集合的文章就介绍到这了,更多相关ES6 Set与WeakSet集合内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解ES6中的Map与Set集合

    集合的概念以及和数组的区别 其实数组也是集合, 只不过数组的索引是数值类型.当想用非数值类型作为索引时, 数组就无法满足需要了. 而 Map 集合可以保存多个键-值对(key-value),  Set 集合可以保存多个元素. 对Map 和 Set 一般不会逐一遍历其中的元素. Map 一般用来存储需要频繁取用的数据,  Set 一般用来判断某个值是否存在其中. ES 5 中对 Map 和 Set 的模拟方法 在ES 5 中,没有 Set和Map集合, 一般使用对象来模拟这两种集合, 对象的属性作

  • ES6中Set与WeakSet集合的深入讲解

    目录 Set是值永不重复的特殊集合 Set集合基础API 关于唯一值的判断 Set集合遍历的3种方式 Set集合案例实践 Set集合与Array数组之间的转换 单个数组去重 多个数组合并去重 获取交集(重复的元素) 判断是否有交集(重复的元素) 获取差集:只返回重复 WeakSet"弱"在哪里? 弱功能 弱引用 总结 Set是值永不重复的特殊集合 每天都用数组,有没有过一个Moment,担心插入了重复的值?使用Set集合吧!Set拥有特殊的数据结构,保证插入的值永远不会重复. Set集

  • ES6中Set和Map数据结构的简单讲解

    目录 Set Map 总结 Set ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set本身是一个构造函数,用来生成 Set 数据结构. const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for (let i of s) { console.log(i); } // 2 3 5 4 上面代码通过add()方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的

  • 详谈ES6中的迭代器(Iterator)和生成器(Generator)

    前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简化数据操作,于是ES6也向JS中添加了这个迭代器特性.新的数组方法和新的集合类型(如Set集合与Map集合)都依赖迭代器的实现,这个新特性对于高效的数据处理而言是不可或缺的,在语言的其他特性中也都有迭代器的身影:新的for-of循环.展开运算符(...),甚至连异步编程都可以使用迭代器 本文将详细介

  • ES6中如何使用Set和WeakSet

    ES6中提供了两新数据结构-Set和WeakSet.Set是类似于数组,但是成员变量的值都是唯一的,没有重复的值.WeakSet也是不重复的值的集合,但是只能用来存放对象. 一.Set使用 (1)Set本身提供了一个构造函数,用来生成Set数据结构. var s = new Set(); [2,2,2,5,8,16,2,1].map(x => s.add(x)) for(i of s){console.log(i)} //2,5,8,16,1 (2)Set()函数可以接受一个数组,作为构造参数,

  • javascript ES6中set集合、map集合使用方法详解与源码实例

    set与map理解 ES6中新增,set集合和map集合就是一种数据的存储结构(在ES6之前数据存储结构只有array,object),不同的场景使用不同的集合去存储数据 set集合 Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用. set集合语法: //创建一个set集合,传参为一个可迭代的对象 const s1 = new Set(iterable); API 名称 类型 简介 Set.add() 原型方法 添加数据 Set.has() 原型方法 判断是否存在一个数据 S

  • ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解

    本文实例讲述了ES6中Set和Map数据结构,Map与其它数据结构互相转换操作.分享给大家供大家参考,具体如下: ES6 的 Set: ES6 提供了新的数据结构──Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. Array和Set对比 都是一个存储多值的容器,两者可以互相转换,但是在使用场景上有区别.如下: ①Array的indexOf方法比Set的has方法效率低下 ②Set不含有重复值(可以利用这个特性实现对一个数组的

  • ES6中Set和Map用法实例详解

    本文实例讲述了ES6中Set和Map用法.分享给大家供大家参考,具体如下: Set ES6提供了新的数据结构Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化. // 例一 var set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4] var s = new Set(); [2, 3, 5, 4, 5, 2, 2].map(x => s.add(x)); fo

  • ES6中的数组扩展方法

    form 转化为真正的数组 先说一下使用场景,在Js中,我们要经常操作DOM,比如获取全部页面的input标签,并且找到类型为button的元素,然后给这个按钮注册一个点击事件,我们可能会这样操作: var inputObjs=document.getElementsByTagName('input'); for(var i=0;i<inputObjs.length;i++){ if(inputObjs[i].type==='button'){ inputObjs[i].onclick=func

  • ES6中Iterator与for..of..遍历用法分析

    本文实例讲述了ES6中Iterator与for..of..遍历用法.分享给大家供大家参考,具体如下: Iterator与for..of..遍历 1.Iterator概念 遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制.JS中有些数据结构具备原生的Iterator接口.为了更好理解这个概念,我们也可以自己写一个Iterator. var it = simIteractor(['hi','ES5']); console.log(it.next()); //Object

随机推荐