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 是唯一得选择