# 应用-新的数据结构
# Map
JavaScript 的对象本质上是键值对的集合,即 hash
结构,但是传统上的对象只能使用字符串作为键,这带来了很大的限制,为了解决这个问题,ES6 提供了 Map 数据结构,类似对象,但是“键”的范围不限于字符串;
- 基本操作
let map = new Map();
map.set("1", "str1"); // 字符串键
map.set(1, "num1"); // 数字键
map.set(true, "bool1"); // 布尔值键
// 还记得普通的 Object 吗? 它会将键转化为字符串
// Map 则会保留键的类型,所以下面这两个结果不同:
alert(map.get(1)); // 'num1'
alert(map.get("1")); // 'str1'
alert(map.size); // 3
- 遍历
如果要在 map 里使用循环,可以使用以下三个方法:
- map.keys() —— 遍历并返回所有的键(returns an iterable for keys),
- map.values() —— 遍历并返回所有的值(returns an iterable for values),
- map.entries() —— 遍历并返回所有的实体(returns an iterable for entries)[key, value]
let recipeMap = new Map([
["cucumber", 500],
["tomatoes", 350],
["onion", 50]
]);
// 遍历所有的键(vegetables)
for (let vegetable of recipeMap.keys()) {
alert(vegetable); // cucumber, tomatoes, onion
}
Map 遍历是有序的
迭代的顺序与插入值的顺序相同。与普通的 Object 不同,Map 保留了此顺序。
Map —— 是一个带键的数据项的集合。
与普通对象 Object 的不同点:
- 任何键、对象都可以作为键。
- 有其他的便捷方法,如 size 属性。
# Set
Set 是一个特殊的类型集合 —— “值的集合”(没有键),它的每一个值只能出现一次。
Set 本身是一个构造函数,用来生成 Set 数据结构,可以接收一个数组作为参数用来初始化。
- 基本操作
const set = new Set([1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9]);
console.log([...set]);
Set 的替代方法可以是一个用户数组,用 arr.find 在每次插入值时检查是否重复。但是这样性能会很差,因为这个方法会遍历整个数组来检查每个元素。Set 内部对唯一性检查进行了更好的优化。
// 数组去重
[...new Set(array)]
// 字符串去重
[...new Set(string)].join('')
向 Set 加入值的时候,不会发生类型转换,类似与全等运算符,但是判断 NaN 的时候会认为等于自身,而全等运算符不会,此外两个对象总是不相等的;
const set = new Set();
set.add(1);
set.add("1");
set.add(NaN);
set.add(NaN);
console.log([...set]);
// [ 1, '1', NaN ]
- 遍历
Array.form() 方法可以将 Set 结构转为数组
const items = new Set([1, 2, 3, 3, 4, 5]);
const array = Array.form(items);
我们可以使用 for..of
或 forEach
来遍历 Set:
let set = new Set(["oranges", "apples", "bananas"]);
for (let value of set) {
console.log(value);
}
Set —— 是一组唯一值的集合。
- 在 Map 和 Set 中迭代总是按照值插入的顺序进行的,所以我们不能说这些集合是无序的,但是我们不能对元素进行重新排序,也不能直接按其编号来获取元素。
# WeakMap
通常,当对象、数组之类的数据结构在内存中时,它们的子元素,如对象的属性、数组的元素都被认为是可达的。
例如,如果把一个对象放入到数组中,那么只要这个数组存在,那么这个对象也就存在,即使没有其他对该对象的引用。
WeakMap 和 Map 的第一个不同点就是,WeakMap 的键必须是对象,不能是原始值
let weakMap = new WeakMap();
let obj = {}
weakMap.set(obj,"ok")
weakMap.set("test","oops");// TypeError Invalid value used as weak map key
现在,如果我们在 weakMap 中使用一个对象作为键,并且没有其他对这个对象的引用 —— 该对象将会被从内存(和map)中自动清除。
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // 覆盖引用
// john 被从内存中删除了!
WeakMap 不支持迭代以及 keys(),values() 和 entries() 方法。
WeakMap 只有以下的方法:
- weakMap.get(key)
- weakMap.set(key, value)
- weakMap.delete(key)
- weakMap.has(key)
# WeakSet
WeakSet 的表现类似:
- 与 Set 类似,但是我们只能向 WeakSet 添加对象(而不能是原始值)。
- 对象只有在其它某个(些)地方能被访问的时候,才能留在 WeakSet 中。
- 跟 Set 一样,WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代。
let visitedSet = new WeakSet();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
visitedSet.add(john); // John 访问了我们
visitedSet.add(pete); // 然后是 Pete
visitedSet.add(john); // John 再次访问
// visitedSet 现在有两个用户了
// 检查 John 是否来访过?
alert(visitedSet.has(john)); // true
// 检查 Mary 是否来访过?
alert(visitedSet.has(mary)); // false