Set与WeakSet 和 Map WeakMap

Set 集合是一种无重复的元素的列表,开发者不会像访问数组那样逐一访问每一个原属 通常的做法是,给定某值是否在集合种
只要Set 实例引用存在就不会被垃圾回收机制回收 Set 类型可以看成为强引用类型
Set 和 WeakSet 其实是跟数据类型,但是跟数组有区别, 使用方法也有区别,作用也有区别

  • add: ƒ add() 添加
    clear: ƒ clear() 删除所有
    delete: ƒ delete() // 删除某一个
    entries: ƒ entries() 返回一个迭代器 值为多个键值对为 [(下标为number),(值,string 会根据集合种的值而来)] Array.entries(): IterableIterator<[number, string]>
    forEach: ƒ forEach() //forEcah 循环

    forEach 接收三个值参数
    Set 集合中 索引的位置
    与第一个参数一样的值
    被遍历Set的本身

        数组和Map 集合的forEach 方法都接收三个参数 前面二个对应的是值 和键名 (对应数组来说就是数值得索引)
    

    has: ƒ has() // 判断一个值是否存在Set 集合种
    keys: ƒ values() 返回一个迭代器 值为集合种所有的键名 返回映射中的键的可迭代对象
    size: (…) // Set 的大小
    values: ƒ values() 返回一个迭代器 值为集合的值 返回数组中的值的可迭代对象 反回数据类型为 string (method) Array.values(): IterableIterator

Map 含多个键值对,集合种的每一个原属 分别存放着可访问的键名和对应的值 Map通常用于缓存频繁取用的值

Set

Set的基本使用 在set集合种不会强制改变数据类型 1,‘1’ 是二个单独的数据

let set = new Set();
// 添加
set.add(1);

set.add("1");

set.add(11);

set.add(111);

//获取大小
console.log(set.size);

// 检查一个值是否存在集合种

console.log(set.has(1)); //true

console.log(set.has(12)); //false

console.log(set.values());

//删除集合种的数据 因为Set 是无重复的元素列表,不像数组那样可以通过下标去删数

// 删除不存在的值会返回false
// console.log(set.delete(12), set); //false Set(4) { 1, '1', 11, 111 }
// // 删除存在的值为 true
// console.log(set.delete(1), set); //true Set(3) { '1', 11, 111 }
// // 删除所有
// console.log(set.clear(), set); //undefined Set(0) {}

//Set 转换为数组

set = new Set([1, 2, 3, 4, 5, 65]);

console.log(set instanceof Set); //true

set = [...set];

console.log(set instanceof Array); //true

Weak Set

为什么会有 Weak Set ? 什么是 Weak Set 集合

WeakSet 的存在是解决Set 的强类型
WeakSet 只存储 对象 的弱引用 并且不能存储原始值 集合种的弱引用如果是对象唯一引用 则会被回收释放对应到的内存
WeakSet 只支持 add has delete 三个方法 使用方法跟set 类型


set = new Set([{}]);

key = {};
set.add(123);

console.log(set.size, set);

key = null;

set1 = new Set();

key = { zx: "紫霞" };
set1.add(key);
console.log(set1); //[ { zx: '紫霞' } ]

// 这里被内存释放不掉  这个key 在上面被引用过不能被内存释放对应的空间
key = null;

console.log(set1); //[ { zx: '紫霞' } ]

let weakSet = new WeakSet([{}, {}]);
let weak = { swk: "神武看" };
weakSet.add(weak);
console.log(weakSet.has(weak)); //true

// 内存释放
weak = null;
// 在WeakSet
console.log(weakSet.has(weak)); //false

//在WeakSet 使用 add 方法传入非对像参数会使报错  has 和delete 传入非对象 返回false
// 在WeakSet 不支持forEach  不支持 size

//WeakSet  能够处理内存中的数据,即使 内存中的数据被释放调用 在WeakSet中 的数据同时被释放掉,不会导致内存泄漏
let weakSet1 = new WeakSet();
obj = { name: 1 };
weakSet1.add(obj); //Invalid value used in weak set

console.log(weakSet1.has({ name: 1 })); //false
console.log(weakSet1.has(obj)); //true
console.log(weakSet1.delete({ name: 1 })); //false
console.log(weakSet1.delete(obj)); //true

Map

Map 类型是存储许多键值对的 有序 列表 键名对应的数据类型是任意数据类型 name:any
键名等价判断是通过 Object.is() 来实现 所有数字的 1, 和字符串的 ‘1’ 会被视为二个不同的key 与对象不同 (如果在对像中 或者JSON 中视为的 一个键,在对象中属性名会被强制类型转换)

Map 有哪些方法可用
/**

  • clear: ƒ clear() 清楚所有
    constructor: ƒ Map() Map 原型
    delete: ƒ delete() 删除某一个
    entries: ƒ entries() 返回一个迭代器 其值为多个键值对
    forEach: ƒ forEach() //迭代
    get: ƒ () 获取 如果不存在的key 则返回 undefined
    has: ƒ has() 判断
    keys: ƒ keys() 返回一个迭代器 值为集合种所有的键名 返回映射中的键的可迭代对象
    set: ƒ () 添加
    size: (…) 查看大小
    values: ƒ values() 返回一个迭代器 值为集合的值 返回数组中的值的可迭代对象
    Symbol(Symbol.iterator): ƒ entries() 迭代属性
    Symbol(Symbol.toStringTag): “Map”
    get size: ƒ size() 获取属性
map = new Map();

map.set("name", "自夏");
map.set("max", 18);

key = {};
key1 = {};

map.set(key, 1);
map.set(key1, 2);

console.log(map);

console.log(map.get("name")); //自夏

console.log(map.has("max")); //true

console.log(map.delete("max")); //true

console.log(map.get("sex")); //undefined

console.log(map.get(key)); //1

console.log(map.has(key)); //true

console.log(map.clear()); //true

console.log(map); // {}
  • Map 和 Set 在设计语言标准时,设计了三个通用的方法 has clear delete 同样也支持 size 属性 Map
    和set 都不会存在重复的值
  • Map 初始化的方法 可以传入构造函数来初始化数组 与 Set 类型 数组中每一个子元素都是一个 子数组 子数组包含一个键 和 值
    的二个元素
  • 初始化构造函数之后 键名有 name sex 分别添加到集合中,Map 可以接受任何数据类型为键名,为了确保能够正常存储到 Map
    集合中之前不能强制转换为其他的数据类型 因而只能将他们存放在数组中 因为这是唯一能够准确区分键名类型的方式 (在数组中 数字 1,和字符串的数字’1’会是二个不同的值)
map = new Map([
  ["name", "竹竹"],
  ["name", "竹竹"],
  ["sex", 19],
]);

console.log(map); //Map(2) { 'name' => '竹竹', 'sex' => 19 }

// 数组和Map 集合的forEach 方法都接收三个参数 前面二个对应的是值 和键名 (对应数组来说就是数值得索引)
map.forEach((value, key, list) => {
  console.log(map === list); //true

  console.log(value, key, list);
});

Weak Map

  • WeakMap 和 WeakSet 是相识得 都是弱引用对应的 Set 或者Map集合
    也拥有存储对象得弱引用,WeakMap集合键必须是一个对象
    如果是非对象就会报错,WeakMap集合存得都是弱引用得对象,如果不存在其他得引用,垃圾回收机制会自动回收该对象,同时会移除WeakMap集合得键值对
  • WeakMap下、是存储许多键值对得无需列表,键名必须是非null 得对象,WeakMap 跟 Map 非常相似 set 存储数据 get
    获取数据,WeakMap初始化跟Map相视,都可以使用二维数组,
  • delete: ƒ delete() 删除
    get: ƒ () 获取
    has: ƒ has() 检测是否存在key
    set: ƒ () 设置
(key = {}), (key1 = {});

let Weak = new WeakMap([
  [key, "zuzu"],
  [key1, "xx"],
]);

console.log(Weak);

console.log(Weak.get(key));

Weak.set({}, "自夏");

console.log(Weak.delete({})); // false

console.log(Weak); 

console.log(Weak.has(key));

运行结果

// 深拷贝
function deep(data) {
  // 第一天条件包含了 null 和 undefined 因为这里不是严格判断
  // 第一个条件  undefined (声明没有赋值) 和 null (一个空指针对象,把一个变量设置为 null 会被垃圾回收机制回收) 在if语句中,都会被自动转为false
  // 第二个条件 判断是否是引用类型  这是使用 typeof来比较得   typeof 检测引用类型有缺点 区分不出来引用类型
  if (data == undefined || typeof data !== "object") {
    return data;
  }

  // 使用 instanceof 来检测引用类型 function、Array、Date,RegExp。

  if (data instanceof Date) return new Date(data);

  if (data instanceof RegExp) return new RegExp(data);

  // 上面拦截了引用类型 用当前得 类型得构造函数创建新的对象

  // 根据当前得得数据类型来构造新的对象
  const newOrg = new data.constructor();

  for (const key in data) {
    // 检测当前对象是否是存在这个key
    if (data.hasOwnProperty(key)) {
      newOrg[key] = deep(data[key]);
    }
  }

  return newOrg;
}

text1 = {};
text2 = {};
text1.text2 = text1;
text2.text1 = text2;
// console.log(deep(text2)); // Maximum call stack size exceeded 栈溢出

使用 WeakMap 解决栈溢出

// 使用 WeakMap 解决栈溢出
function deeps(data, newWeakMap = new WeakMap()) {
  // 第一天条件包含了 null 和 undefined 因为这里不是严格判断
  // 第一个条件  undefined (声明没有赋值) 和 null (一个空指针对象,把一个变量设置为 null 会被垃圾回收机制回收) 在if语句中,都会被自动转为false
  // 第二个条件 判断是否是引用类型  这是使用 typeof来比较得   typeof 检测引用类型有缺点 区分不出来引用类型
  if (data == undefined || typeof data !== "object") {
    return data;
  }

  // 使用 instanceof 来检测引用类型 function、Array、Date,RegExp。

  if (data instanceof Date) return new Date(data);

  if (data instanceof RegExp) return new RegExp(data);

  // 上面拦截了引用类型 用当前得 类型得构造函数创建新的对象

  // 获取当前得 WeakMap 里面是否有对应得值
  // WeakMap集合键必须是一个对象 上面有提到
  const hasMap = newWeakMap.get(data);

  // 当前得WeakMap 中存在值 就返回 不存在继续往下面走
  if (hasMap) return hasMap;

  // 根据当前得得数据类型来构造新的对象
  const newOrg = new data.constructor();

  // 在 WeakMap 中设置值
  newWeakMap.set(data, newOrg);

  for (const key in data) {
    // 检测当前对象是否是存在这个key
    if (data.hasOwnProperty(key)) {
      newOrg[key] = deeps(data[key], newWeakMap);
    }
  }

  return newOrg;
}

text1 = {};
text2 = {};
text1.text2 = text1;
text2.text1 = text2;
console.log(deeps(text2)); 

当使用 WeakMap 和普通得 Map 时 最主要考虑得问题是 是否用对象最为集合和得键名 如果是 WeakMap
是最好得选择,当数据不可在访问后,WeakMap集合会自动回收,有效避免了内存泄漏问题,也优化得内存使用问题

如果使用非对象作为键名Map 是唯一得选择

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值