JS的set和map
1.set()
***Set*有点*类似于Array数组*,但是和数组的区别是*Set的元素不能重复*。
Set常见的属性:
size:返回Set中元素的个数;
Set常用的方法:
add(value):添加某个元素,返回Set对象本身;
delete(value):从set中删除和这个值相等的元素,返回boolean类型;
has(value):判断set中是否存在某个元素,返回boolean类型;
clear():清空set中所有的元素,没有返回值;
forEach(callback, [, thisArg]):通过forEach遍历set;
set()常用功能就是数组去重
const array = [10, 10, 12, 12, 12, 15, 17]
const set = new Set(array)
const newArray = Array.from(set)
const newArray1 = [...set]
console.log(set)
console.log(newArray)
console.log(newArray1)
Array.from()
静态方法从可迭代或类数组对象创建一个新的浅拷贝的数组实例
2.WeakSet使用
和set的区别
区别一:WeakSet中只能存放对象类型,不能存放基本数据类型;
区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收 也就是只有强引用才不会被gc回收
3.js Map
Map
对象是键值对的集合。Map
中的一个键只能出现一次;它在 Map
的集合中是独一无二的。Map
对象按键值对迭代——一个 for...of
循环在每次迭代后会返回一个形式为 [key,value]
的数组。迭代按插入顺序进行,即键值对按 set()
方法首次插入到集合中的顺序(也就是说,当调用 set()
时,map 中没有具有相同值的键)进行迭代。
在 JavaScript 中实现“键/值”式存储可以使用 Object 来方便高效地完成,也就是使用对象属性作为键,再使用属性来引用值。但这种实现并非没有问题,为此 TC39 委员会专门为“键/值”存储定义了一个规范。
作为 ECMAScript 6 的新增特性,Map 是一种新的集合类型,为这门语言带来了真正的键/值存储机制。Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。具体实践中使用哪一个,还是值得细细甄别。
使用 new 关键字和 Map 构造函数可以创建一个空映射:
const m = new Map();
如果想在创建的同时初始化实例,可以给 Map 构造函数传入一个可迭代对象,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中(类似于二维数组):
const m = new Map([
["小明", 100],
["小红", 90],
["小兰", 99]
]);
Array.from(m); // [["小明", 100],["小红", 90],["小兰", 99]]
m.size //size属性获得map的大小
set(): 给Map实例添加键/值对:
const m = new Map();
m.set("小明", 100).set("小红", 100);
m.get("小红"); // 100
m.get("abc"); // 不存在为undefined
has(): 通过键查询是否存在, 返回布尔值:
const m = new Map();
m.set("小明", 100).set("小红", 100);
m.has("小明"); // true
m.has("abc"); // false
delete(): 删除对应键的数据,返回布尔值,表示是否删除成功:
const m = new Map();
m.set("小明", 100).set("小红", 100);
m.delete("小红"); // true
Array.from(m); // [["小明", 100]]
clear(): 清空Map实例:
const m = new Map();
m.set("小明", 100).set("小红", 100);
m.clear();
Array.from(m); // []
keys(): 返回以插入顺序生成键的迭代器;
values(): 返回以插入顺序生成值的迭代器;
entries(): 返回插入顺序生成[key, value]形式的数组。
// keys()
const m = new Map();
m.set("小明", 100).set("小红", 100);
Array.from(m.keys()); // ['小明', '小红']
// values()
Array.from(m.values()); // [100, 100]
// entries()
Array.from(m.entries()); // [["小明", 100],["小红", 100]]
平常的使用: 比如通过名字快速查找对应的考试成绩。
有的人这时候就要说了,我用对象一样也可以做到呀。嗯~,没毛病。
but,but,如果比较注重性能的话就有必要使用Map了:
选择 Object 还是 Map
对于多数 Web 开发任务来说,选择 Object 还是 Map 只是个人偏好问题,影响不大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。
键的类型
Map | Objcet | |
---|---|---|
键的类型 | 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 | 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 |
键的顺序 | Map 中的键是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 | 虽然 Object 的键目前是有序的,但并不总是这样,而且这个顺序是复杂的。因此,最好不要依赖属性的顺序。 |
Size | Map 的键值对个数可以轻易地通过 size 属性获取。 | Object 的键值对个数只能手动计算。 |
迭代 | Map 是 可迭代的 的,所以可以直接被迭代。 | Object 没有实现 迭代协议,所以使用 JavaSctipt 的 for…of 表达式并不能直接迭代对象。 |
对象可以实现迭代协议,或者你可以使用 Object.keys 或 Object.entries 。 for…in 表达式允许你迭代一个对象的可枚举属性。 | ||
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
WeakMap
WeakMap 的 key 只能是 Object
类型。 原始数据类型 是不能作为 key 的(比如 Symbol
)。
在 JavaScript 里,map API 可以 通过使其四个 API 方法共用两个数组(一个存放键,一个存放值)来实现。给这种 map 设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该 map 取值的时候,需要遍历所有的键,然后使用索引从存储值的数组中检索出相应的值。
但这样的实现会有两个很大的缺点:
- 首先赋值和搜索操作都是 O(*n)* 的时间复杂度(n 是键值对的个数),因为这两个操作都需要遍历全部整个数组来进行匹配。
- 另外一个缺点是可能会导致内存泄漏,因为数组会一直引用着每个键和值。这种引用使得垃圾回收算法不能回收处理他们,即使没有其他任何引用存在了。
相比之下,原生的 WeakMap
持有的是每个键对象的“弱引用”,这意味着在没有其他引用存在时垃圾回收能正确进行。原生 WeakMap
的结构是特殊且有效的,其用于映射的 key _只有_在其没有被回收时才是有效的。
正由于这样的弱引用,WeakMap
的 key 是不可枚举的(没有方法能给出所有的 key)。如果 key 是可枚举的话,其列表将会受垃圾回收机制的影响,从而得到不确定的结果。因此,如果你想要这种类型对象的 key 值的列表,你应该使用 Map
。