Set和Map数据结构

Set

Set类似于数组,但是成员的值都是唯一的,没有重复的值
Set本身是一个构造函数,可以接受一个数组(或者具有iterable接口的其他数据结构)作为参数。

去除数组重复成员的方法

  1. 扩展运算符
[...new Set(array)]
  1. Array.from方法可以将Set结构转为数组
Array.from(new Set(array))

注意点

  1. 向Set加入值时,不会发生类型转换。在Set内部判断两个值是否不同,类似于精确相等运算符(=),区别是:NaN等于自身,而=认为NaN不等于自身。
    let set = new Set();
    set.add(NaN);
    set.add(NaN);
    console.log(set);//Set {NaN}
    console.log(NaN === NaN); //false
  1. 注意两个对象总是不相等============
//由于两个空对象不相等,所以它们被视为两个值
    let set = new Set();
    set.add({});
    console.log(set.size);
    set.add({});
    console.log(set.size);  

Set实例的属性和方法

属性

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

方法

操作方法
  1. add(value) 添加某个值,返回Set结构本身
    s.add(1).add(2);
    
  2. delete(value) 删除某个值,返回布尔值,表示删除是否成功
  3. has(value) 判断该值是否为Set的成员,返回布尔值
  4. clear() 删除所有成员,没有返回值
遍历方法

Set的遍历顺序是插入顺序

  1. keys() 返回键名的遍历器
  2. values() 返回键值的遍历器
  3. entries() 返回键值对的遍历器
  4. forEach() 使用回调函数遍历每个成员

前三个方法返回的都是遍历器对象,Set结构的键值和键名是同一个值(keys和values方法的行为完全一致)(也可以理解为没有键名,只有键值)
Set结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。因此,可以直接用for…of循环遍历Set。

Set.prototype[Symbol.iterator] === Set.prototype.values //true

forEach()用于对每个成员执行某种操作,没有返回值,表示绑定处理函数内部的this对象

mySet.forEach(callback[, thisArg])

扩展运算符内部使用for…of循环
数组的map和filter方法也可以用于Set
想在遍历操作中,同步改变原来的Set结构

let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
set = new Set(Array.from(set, val => val > 2));
  • Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
    Array.from(arrayLike[, mapFn[, thisArg]])
    arrayLike 想要转换成数组的伪数组对象或可迭代对象。
    mapFn 可选如果指定了该参数,新数组中的每个元素会执行该回调函数。

WeakSet

WeakSet作为构造函数,可以接受一个数组或者类似数组的对象(具有Iterable接口的对象)作为参数。数组的成员会自动成为WeakSet实例对象的成员。(数组的成员只能是对象,因为WeakSet的成员只能是对象)
WeakSet结构与Set类似,但它与Set有两个区别

与Set的区别

  • WeakSet的成员只能是对象,不能是其他类型的值。
  • WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还存在与WeakSet中。

注意点

  1. WeakSet的成员是不适合引用的,因为它随时会消失。
  2. WeakSet不可遍历,因为WeakSet内部有多少个成员,取决于垃圾回收处理机制有没有运行,而且垃圾回收处理机制何时运行是不可预测的。因为成员都是弱引用,随时可能消失。

适用场景

适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在WeakSet里面的引用就会自动消失。
WeakSet的用处,存储DOM节点,不用担心节点从文档移除时,会发生内存泄漏。

WeakSet结构的方法

(没有size属性,没有办法遍历它的成员,无法清空)

  1. add(value) 添加新成员
  2. delete(value) 清除某个指定成员
  3. has(value) 判断某个值是否在WeakSet实例中

Map

js的对象本质上是键值对的集合,只能用字符串当做键。Map类似于对象,也是键值对的集合。但“键”的范围不限于字符串,各种类型的值都可以当做键。
Map也可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组任何具有Iterator接口、且每个成员都是一个双元素的数组的数据结构都可以作为Map构造函数的参数。Set和Map都可以用来生成新的Map。

const map = new Map([
    ['name', '张三'],
    ['age', '18'],
]);
map.size //2
map.has('name') //true
map.get('name') //'张三'

注意点

只有对同一个对象的引用,Map结构才将其视为同一个键。Map的键实际上是跟内存地址绑定的,只要内存地址不一样就视为两个键。这就解决了同名属性碰撞的问题。

// 实际上是两个键
let map = new Map();
map.set(['a'], 555);
console.log(map.get(['a']));// undefined

let map1 = new Map();
let array = ['a'];
map1.set(array, 555);
console.log(map1.get(array));// 555

let map2 = new Map();
let k1 = ['a'];
let k2 = ['a'];
map2.set(k1, 111).set(k2, 222);
console.log(map2.get(k1));// 111
console.log(map2.get(k2));// 222

Map实例的属性和方法

属性

size属性,返回Map结构的成员总数。

方法

操作方法
  1. set(key, value) 设置键名key对应的键值为value,返回整个Map结构。
    let map = new Map();
    map.set('foo',true).set('bar',false);
    
  2. get(key) 读取key对应的键值
  3. has(key) 判断某个键是否在当前Map对象之中,返回布尔值
  4. delete(key) 删除某个键,返回布尔值
  5. clear() 清除所有成员,无返回值
遍历方法

三个遍历器生成函数和一个遍历方法
Map的遍历顺序是插入顺序

  1. keys() 返回键名的遍历器
  2. values() 返回键值的遍历器
  3. entries() 返回所有成员的遍历器
  4. forEach() 使用回调函数遍历每个成员
    Map结构的默认遍历器接口(Symbol.iterator属性),就是entries()
map[Symbol.iterator] === map.entries //true

WeakMap

WeakMap与Map结构类似,也是用于生成键值对的集合。

与Map的区别

  1. WeakMap只接受对象作为键名(null除外)
  2. WeakMap的键名所执行的对象,不计入垃圾回收机制

使用场景

想往对象上添加数据,但又不想干扰垃圾回收机制,就可以使用WeakMap。WeakMap的专用创和就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏。

注意点

WeakMap弱引用的只是键名,不是键值,键值依然是正常引用。
键值obj是正常引用,所以,即使在WeakMap外部消除了obj的引用,WeakMap内部的引用依然存在

let wm = new WeakMap();
let key = {};
let obj = {foo: 1};
wm.set(key, obj);
obj = null;
console.log(wm.get(key)); //{foo: 1}

属性和方法

  1. WeakMap没有遍历操作,也没有size属性。
  2. 无法清空,不支持clear方法

方法

  1. set(key,value)
  2. get(key)
  3. has(key)
  4. delete(key)

用途

部署私有属性

Countdown类的两个内部属性_counter和_action,是实例的弱引用,所以如果删除实例,它们也就随之消失,不会造成内存泄漏。

const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  dec() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}
const c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
// DONE
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值