Map和Set都叫做集合,但是它们也有所不同。Set常被用来检查对象中是否存在某个键名,Map集合常被用来获取已存的信息。
Set是有序列表,含有相互独立的非重复值。Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
创建Set:
let set = new Set();
console.log(set);
//在浏览器控制台的输出结果
Set(0) {}
size:(...)
__proto__:Set
[[Entries]]:Array(0)
length:0
let obj = new Object()
console.log(obj)
//在控制台输出对象
Object {}
__proto__:
从输出结果看,Set和Object有明显的区别,
接着,我们看一下Set的原型有哪些:
Set.prototype.size
返回Set对象的值的个数。
Set.prototype.add(value)
在Set对象尾部添加一个元素。返回该Set对象。
Set.prototype.entries()
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法和Map对象保持相似, 每个值的键和值相等。
Set.prototype.forEach(callbackFn[, thisArg])
按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。
Set.prototype.has(value)
返回一个布尔值,表示该值在Set中存在与否。
let set = new Set();
set.add('haha');
set.add(Symbol('haha'));
console.log(set.size); //2
console.log(set);
Set(2) {"haha", Symbol(haha)}
size:(...)
__proto__:Set
[[Entries]]:Array(2)
0:"haha"
1:Symbol(haha)
length:2
console.log(set.has('haha')) // true
迭代Set
Set既然提供了entries和forEach方法,那么他就是可迭代的。但如果你使用for in来迭代Set,你不能这样做:
for(let i in sets) {
console.log(i); //不存在
}
for in迭代的是对象的key,而在Set中的元素没有key,使用for of来遍历
for(let value of sets) {
console.log(value);
}
//"haha"
//Symbol(haha)
//如果你需要key,则使用下面这种方法
for(let [key, value] of sets.entries()) {
console.log(value, key);
}
//"haha" "haha"
//Symbol(haha) Symbol(haha)
forEach操作Set:Set本身没有key,而forEach方法中的key被设置成了元素本身。
sets.forEach((value, key) => {
console.log(value, key);
});
//"haha" "haha"
//Symbol(haha) Symbol(haha)
sets.forEach((value, key) => {
console.log(Object.is(value, key));
});
//true true
Set和Array的转换
Set集合的特点是没有key,没有下标,只有size和原型以及一个可迭代的不重复元素的类数组。我们可以把一个Set集合转换成数组,也可以把数组转换成Set
//数组转换成Set
const arr = [1, 2, 2, '3', '3']
let set = new Set(arr);
console.log(set) // Set(3) {1, 2, "3"}
//Set转换成数组
let set = new Set();
set.add(1);
set.add('2');
console.log(Array.from(set)) // (2) [1, "2"]
使用Set集合的不可重复性来处理 重复性:
const arr = [1, 1, 'haha', 'haha', null, null]
let set = new Set(arr);
console.log(Array.from(set)) // [1, 'haha', null]
console.log([...set]) // [1, 'haha', null]
Weak Set集合
语法:new WeakSet([iterable]);
和Set的区别:1 WeakSet 对象中只能存放对象值, 不能存放原始值, 而 Set 对象都可以. 2、WeakSet 对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样,WeakSet 对象是无法被枚举的,没有办法拿到它包含的所有元素.
let set = new WeakSet();
const class_1 = {}, class_2 = {};
set.add(class_1);
set.add(class_2);
console.log(set) // WeakSet {Object {}, Object {}}
console.log(set.has(class_1)) // true
console.log(set.has(class_2)) // true
Map是存储许多键值对的有序列表,key和value支持所有数据类型。
如果说Set像数组,那么Map更像对象。而对象中的key只支持字符串,Map更加强大,支持所有数据类型,不管是数字、字符串、Symbol等。
// 一个空Map集合
let map = new Map()
console.log(map)
使用对象做key
let map = new Map();
const key = {};
map.set(key, 'HelloWorld');
console.log(map.get(key))
Map同样可以使用forEach遍历key、value
let map = new Map();
const key = {};
map.set(key, 'HelloWorld');
map.set('name', 'haha');
map.set('id', 1);
map.forEach((value, key) => {
console.log(key, value)
})
//Object {} "HelloWorld"
//"name" "haha"
//"id" 1
Maps 和 Objects 的区别
一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
Weak Map
有强Map,就有弱Map。和Set要解决的问题一样,希望不再引用Map的时候自动触发垃圾回收机制。那么,你就需要Weak Map。
let map = new WeakMap();
const key = document.querySelector('.header');
map.set(key, 'Hello World');
map.get(key) // "Hello World"
//移除该元素
key.parentNode.removeChild(key);
key = null;
简单总结: Set集合可以用来过滤数组中重复的元素,只能通过has方法检测指定的值是否存在,或者是通过forEach处理每个值。Weak Set集合存放对象的弱引用,当该对象的其他强引用被清除时,集合中的弱引用也会自动被垃圾回收机制回收,追踪成组的对象是该集合最好的使用方式。Map集合通过set()添加键值对,通过get()获取键值,你可以把它看成是比Object更加强大的对象。Weak Map集合只支持对象类型的key,所有key都是弱引用,当该对象的其他强引用被清除时,集合中的弱引用也会自动被垃圾回收机制回收,为那些实际使用与生命周期管理分离的对象添加额外信息是非常适合的使用方式。