美文网首页
JavaScript之 Set & Map数据结构

JavaScript之 Set & Map数据结构

作者: 又菜又爱分享的小肖 | 来源:发表于2021-06-27 09:59 被阅读0次

ES6提供了新的数据结构——Set。类似于数组, 但是成员的值是唯一的, 没有重复

Set本身是一个构造函数, 用来生成Set数据结构。

        const s = new Set();
        let arr = [1,1,3,4,5,5];
        arr.forEach(item=>{
            s.add(item);
        })
        for(let i of s){
            console.log(i); // 1,3,4,5
        }

通过add方法进行添加成员, 结果表明Set结构不会添加重复的值。

Set可以接收一个数组作为参数, 用来初始化。

        const set = new Set([1,1,2,2,3])
        console.log([...set]); // [1,2,3]
        let size = set.size
        console.log(size); // 3   size展示set的个数

向Set加入值时不会发生类型转换, 所以5和“5”是两个不同的值。 Set内部判断两个值是否相同使用的算法叫做“Same-value equality”,它类似于精确相等运算符(===),主要是区别是NaN等于自身,而精确相等运算符认为NaN不等于本身。

        let arr = new Set([NaN,NaN]);
        console.log(arr); // Set{NaN}
        console.log(NaN === NaN); // false

上面代码添加了两个NaN,但是实际上只能添加一个。这表明,在Set内部,两个NaN是相等的。

另外,两个对象总是不相等的。

        let arr = new Set([{},{}]);
        console.log(arr); // Set{}{}

由于两个空对象表示精确相等,它们的值是相等的,但是它们的内存地址是不相等的,所以它们被视为两个值。

Set实例的属性和方法

        Set.prototype.constructor: 构造函数,默认就是Set函数
        Set.prototype.size: 返回Set实例的成员总数

Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。
add(value):添加某个值,返回Set结构本身。
delete(value):删除某个值,返回布尔值,表示是否删除成功。
has(value):返回一个布尔值,表示参数是否为Set的成员。
clear():清除所有成员,没有返回值。

下面是一个对比,判断是否包括一个objeck结构和set结构的写法不同。

        //对象写法
        let obj = {
            width:1,
            height:2
        }
        if(obj.width){
            //存在执行代码
        }
        //Set的写法
        let arr = new Set();
        arr.add('width');
        arr.add('height')
        if(arr.has('width')){
            //有执行代码
        }

Array.from方法可以将Set结构转为数组。

        function dedupe(arr) {
            return Array.from(new Set(arr));
        }
        dedupe([1,1,2,3]);//[1,2,3]  

遍历操作

Set结构的实例有4个遍历方法,可用于遍历成员。
keys():返回键名。
values():返回键值。
entries():返回键值对。
forEach():使用回调遍历每个成员。
Set结构的实例默认可遍历,其默认遍历器生成函数就是它的values方法。

        console.log(Set.prototype[Symbol.iterator] === Set.prototype.values); //true

这意味着,可以省略values方法,直接用for...of 循环遍历Set。

WeakSet

WeakSet结构与Set类似,也是不重复的值的集合。但是,它与Set有两个区别。
第一WeakSet的成员只能是对象,而不能是其他类型的值。

        const ws = new WeakSet();
        ws.add(1);//报错

第二,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还存在与WeakSet之中。
这是因为垃圾回收机制依赖引入计数,如果一个值的引用次数不为0,则不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet里面的引用都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在WeakSet的引用就会自动消失。
由于上面的特点,WeakSet的成员是不适合引用的,因为它会随时消失,WeakSet内部有多少个成员取决于垃圾回收机制有没有运行,运行前后的成员个数可能是不一样的,而垃圾回收机制什么时候回收也是不能预测的,所以ES6规定WeakSet不能遍历。
WeakSet结构有以下3个方法。

        WeakSet.prototype.add(value): 添加一个成员
        WeakSet.prototype.delete(value): 删除一个成员
        WeakSet.prototype.has(value): 返回一个布尔值,表示这个值是否在WeakSet实例中

WeakSet没有size属性,因为没有办法遍历其成员。

Map

JavaScript的对象本质上是键值对的集合,但是只能用字符串作为键。这给它的使用带来了很大的限制。

        const data = {};
        const element = document.querySelector('#mydiv');
        data[element] = 'meta';
        console.log(data); // {[object HTMLDivElement]: "meta"}

将一个DOM节点作为对象data的键,但是由于对象只接收字符串作为键名,所以element被自动转换为[object HTMLDivElement]。
为了解决这个问题,提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,如果需要键值对,Map比Objeck更适合。

        let map = new Map();
        let obj = {name:'肖'};
        map.set(obj,'对象'); // 设置值
        map.get(obj); //取值
        map.delete(obj); //删除值
        map.has(obj); //判断值 返回一个布尔值

作为构造函数,Map也可以接收一个数组作为参数。该数组的成员是一个个表示键值对的数组。

let map = new Map([[name,'xiao'],[age,21]]);

        //实例上执行下面算法
        const arr = [['name','xiao'],['age',21]];
        let map = new Map();
        arr.forEach(([key,value]) =>{ //解构  let [key, value] = item;
            map.set(key,value)
        })
        let map = new Map();
        map.set(['a'],1);
        console.log(map.get(['a'])); //undefined

上面的set和get方法表面上是针对同一个键,但是两个值的内存地址不一样,所以是两个值,get(['a'])为undefined
同理,同样的值的两个实例在Map结构中被视为两个键。

        const map = new Map();
        const k1 = ['a'];
        const k2 = ['a'];
        map.set(k1, 111).set(k2,222);
        map.get(k1); //111
        map.get(k2); //222

Map的键实际上是和内存绑定的,只要内存地址不一样,就被视为两个键。就解决了同名属性碰撞的问题,我们扩展别人的库时,如果使用对象键名,不用担心自己的属性与原作者的属性同名。
Map的遍历方式和Set是一样的,因为是可遍历的,所以map也有自己的size属性。

WeakMap

WeakMap的用法和含义几乎和WeakSet一样,也是弱应用,不会被垃圾回收机制回收。不能被遍历,所以就没有size属性和遍历方法。

相关文章

网友评论

      本文标题:JavaScript之 Set & Map数据结构

      本文链接:https://www.haomeiwen.com/subject/nqwzyltx.html