JS笔记之JS数据类型(五)
JS笔记之JS数据类型(五)
1 Map
map 是一个带键的数据项的集合,他和object很像, 但是map允许任意类型的键,而对象的键只能是 字符串和symbol,不管用什么当做对象的key(除了symbol),都会被js转化为字符串。
1.1 方法
- new Map() :创建一个map。
- map.set(key, value):根据键设置值。map在创建时保留了值插入的顺序。
- map.get(key):根据键来返回值,如果不存在key,则返回undefined。
- map.has(key):如果key存在返回true,不存在返回false。
- map.delete(key):删除指定的key。
- map.clear():清空map。
- map.size:返回当前元素的个数。
在使用map获取key的值或者设置值时 应该使用 map.get() 或者 map.set() 。
1 | let map = new Map(); |
map比较键的方法:使用sameValueZero算法来比较键是否相等,他和严格等于 === 差不多,但区别是 NaN是等于NaN的,所以NaN也可以被用作键。
map 在设置key的时候返回的是他自身,所以可以被链式调用,例如:
1 | let mapObj = new Map(); |
1.2 Map 迭代
在map里面循环可以使用下面的三个方法:
map.keys() 遍历并返回一个包含所有键的可迭代对象。
map.values() 遍历并返回一个包含所有值的可迭代对象。
map.entries() 遍历并返回一个包含所有实体 [key, value] 的可迭代对象,for…of 在默认情况下才 就是使用的此方法。
map.forEach() 和数组一样,对每个键值对执行一个函数。
1
2
3
4// 对每个键值对 (key, value) 运行 forEach 函数
recipeMap.forEach( (value, key, map) => {
alert(`${key}: ${value}`); // cucumber: 500 etc
});
1.3 将对象转化为Map -> Object.entries
当new 一个Map() 对象时,我们可以使用一个带键值对的数组(或者其他的可迭代对象)进行初始化,例如:
1 | // 键值对 [key, value] 数组 |
如果使用普通的对象来创建map,我们可以使用内建方法 Object.entries(obj),该方法返回对象的键值对数组。
1.4 将Map转化为建对象 Object.fromEntries(obj)
它与 Object.entries(obj)是相反的,给定一个具有[key, value] 的数组,他会根据数组创建一个对象。
1 | let prices = Object.fromEntries([ |
例如 将一个map的数组转化为一个普通对象传输给第三方的接口
1 | let obj = Object.fromEntries(map) |
2 set
set 是一个特殊的类型集合 – 值的集合,他没有键,而且他的值只能出现一次。
2.1 方法
- new Set(iterable): 创建一个set,如果提供了一个可迭代对象(通常是数组),将会从数组里面复制到set中。有重复的值,自动删除。
- set.add(value):添加一个值返回set 本身,可以像map那样链式调用。
- set.delete(value): 删除值,存在返回true,不存在返回false。
- set.has(value):如果value在set中,返回true,不在返回false。
- set.clear():清空set。
- set.size:返回当前元素的个数。
2.2 set 迭代
可以使用for…of 或者 forEach 来迭代set
1 | let set = new Set(["oranges", "apples", "bananas"]); |
在forEach的回调函数中有三个参数, 一个是value,另一个也是 value,最后是目标对象。
在map中的迭代方法在set中同样适用。
3 WeakMap
在JS中 数组或者对象中的key 或者value,他们都是认为是可达的,如果一个对象被传入数组中,那么我们认为如果这个数组存在,那么这个对象也一定是可达的。在 map 中的 key或者是value 也是同样的道理。
JS垃圾回收中JS引擎在值可达和被可能引用的时候,会将值保存在内存中。
1 | let john = { name: "John" }; |
当某个对象作为map的键的时候, 我们也认为改对象是可达的,他会占用内存,且不会被垃圾回收。
1 | let john = { name: "John" }; |
WeakMap 和 Map 的区别
- 在键上的区别
- WeakMap 的键必须是对象,不能是原始值。
- 方法上的区别
- 只支持 has() get () set() delete() 方法, 不支持 keys() values() entries()
- 不能迭代。
WeakMap 的使用场景主要的使用场景:
额外数据的存储。
假如要处理另一些代码的数据,或者是第三方库的数据并且要存储一些相关的数据,那么这时候这些数据就应该和这个对象共存亡。将这些数据存储到WeakMap 中,并使用该对象作为这些数据的键,当改对象对垃圾回收后,这些数据也会被回收。
1
2
3 let weakMap = new WeakMap();
// 如果 john
weakMap.set(john, 'some data');
做数据缓存
可以缓存函数返回的结果,一遍多次电泳不需要重新计算。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 let cache = new WeakMap();
// 计算并记结果
function process(obj) {
if (!cache.has(obj)) {
let result = /* calculate the result for */ obj;
cache.set(obj, result);
}
return cache.get(obj);
}
// 📁 main.js
let obj = {/* some object */};
let result1 = process(obj);
let result2 = process(obj);
// ……稍后,我们不再需要这个对象时:
obj = null;
// 无法获取 cache.size,因为它是一个 WeakMap,
// 要么是 0,或即将变为 0
// 当 obj 被垃圾回收,缓存的数据也会被清除
4 WeakSet
WeakSet 和 Set 的区别
- WeakSet 的元素只能是对象。
- 对象只有在其他某个地方能被访问的时候,再能六在 WeakSet中。
- 只支持add() has() delete() 不支持size和 keys() ,并且不可迭代。
weakSet也可以作为额外的空间,但是只能是针对是/否的事实。例如:
1 | let visitedSet = new WeakSet(); |
5 总结
map 是一个带有键的数据的集合。与普通的对象不同的是,他的键可以是任意数据类型。有不同结构的方法,例如:map.size
set 是一组唯一值的集合。
在map和set 迭代总是按照插入的顺序,所以不能说他们的元素是无序的,但也不能对元素重新排序,也不能按照编号来取数据。
WeakMap 类似于Map ,但是只能设置键为对象,并且这些对象一旦在其他地方无法访问,则这个对象就会被垃圾回收,且WeakMap 对应的值也会被删除回收。
WeakSet 类似于Set,但是只能存储对象,并且这些对象一旦在其他地方无法访问,那么也会在WeakSet中删除回收。
WeakMap WeakSet 被用作主要对象存储之外的辅助数据结构。例如缓存的使用场景。