# Map 和 Set

# Map, WeakMap

# Map

Map 有些像 JSON,是键值对的结合(Hash 结构)。但是 JSONKey 只能是字符串,Mapkey 可以是任意对象。

let obj = {name: '石兴龙'}
let j = {}
j[obj] = obj;  // 此处的 [obj] 会转化为 [object Object]

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

由此我们可以得出

  • Json 提供的是 字符串:值 的关系
  • Map 提供的是 值:值的关系

显然 Map 是一种更加完善的 Hash 结构。

作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

const map = new Map([
  ['name', '石兴龙'],
  ['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "石兴龙"
map.has('title') // true
map.get('title') // "Author"

上面代码在新建 Map 实例时,就指定了两个键name和title。

Map构造函数接受数组作为参数,实际上执行的是下面的算法。

在 Map 中 key 是唯一的,如果多次赋值同一个Key 那么值钱的值会被替换掉

const map = new Map([
  ['name', '石兴龙'],
  ['title', 'Author'],
  ['socialMedia', '']
]);
map.set('socialMedia', '微信:Codingxiaoshi')
map.set('socialMedia', 'Codingxiaoshi')
map.get('socialMedia'); // Codingxiaoshi

Map 中的 key 是根据内存地址绑定的。我们可以来做过实验

let key1 = ['1'];
let key2 = ['1'];
const map = new Map();
map.set(key1, '石兴龙');
map.set(key2, '微信:Codingxiaoshi');

map.get(key1) // 石兴龙
map.get(key2) // 微信:Codingxiaoshi

我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。

# Map 的方法

set() 设置一对元素

const map = new Map();
map.set('name', '石兴龙')

get() 根据 key 获取获取某个元素

const map = new Map([[ 'name', '石兴龙' ]]);
map.get('name'); // 石兴龙

has() 判断某组 key 是否存在

const map = new Map([[ 'name', '石兴龙' ]]);
map.has('name'); // true
map.has('phone'); // false

delete() 删除某组元素

const map = new Map([[ 'name', '石兴龙' ]]);
map.delete('name');
map.has('name'); // false
map.size; // 0

clear() 清空 Map 实例

const map = new Map([[ 'name', '石兴龙' ]]);
map.clear('name');
map.size; // 0

遍历的方法

我们处理用 for (... of) 遍历之外,还可以使用 Map 提供的方法。

const map = new Map([
  [ 'name', '石兴龙' ],
  [ '微信', 'Codingxiaoshi' ],
]);
for (let [k,v] of map) {
  console.log(k, v);
}

keys():返回键名的遍历器。

const map = new Map([
  [ 'name', '石兴龙' ],
  [ '微信', 'Codingxiaoshi' ],
]);
map.keys(); // name, 微信

values():返回键值的遍历器。

const map = new Map([
  [ 'name', '石兴龙' ],
  [ '微信', 'Codingxiaoshi' ],
]);
map.values(); // 石兴龙, Codingxiaoshi

entries():返回所有成员的遍历器。

const map = new Map([
  [ 'name', '石兴龙' ],
  [ '微信', 'Codingxiaoshi' ],
]);
map.entries(); //  {"name" => "石兴龙", "微信" => "Codingxiaoshi"}

forEach():遍历 Map 的所有成员。

const map = new Map([
  [ 'name', '石兴龙' ],
  [ '微信', 'Codingxiaoshi' ],
]);
map.forEach(function(value, key, map) {
  console.log("Key: %s, Value: %s", key, value);
});

# WeakMap

WeakMap 结构与Map结构类似,也是用于生成键值对的集合。但是 WeakMap 的 key 只能是对象。

const map = new WeakMap();
map.set('name', '石兴龙'); TypeError: name is not an object!

其次,WeakMap 引用的键名不会计入垃圾回收机制。只要这个变量不在被引用了,那么他在 WeakMap 中也会自动被移出。

TIP

WeakMap 主要解决的是对象引用过程中产生的内存泄漏问题。

这样一来 WeakMap 则失去了被遍历的功能,因为 WeakMap 中的元素随时都会消失。上一步还能遍历出来,下一步则消失了。这样是没有意义的。(即没有keys()、values()和entries()方法),也没有size属性。

const wm = new WeakMap();

// size、forEach、clear 方法都不存在
wm.size // undefined
wm.forEach // undefined
wm.clear // undefined

# Set, WeakSet

# Set

Set 类似于数组的数据结构,但所有的元素都是唯一的,不允许出现重复的值。Set 函数接受一个 数组或者 具有 具有 iterable 接口的任意数据类型,来初始化元素列表

const s = new Set([1,2,3,4,5,5,5,5]);
for (let i of s) {
    console.log(i); // 依次输出:1,2,3,4,5
}
console.log(s.size)  // 5

s.size 代表集合的长度。

Set.add() 方法来增加元素列表,当 add 已经存在的元素时,将舍弃。Set 内部是通过类似 === 三等的判断条件来确定数据是否重复所以 两个空的JSON是可以被添加到Set集合中的

const s = new Set();
s.add(1)
s.add(2)
s.add(2)
s.add(2)
s.add(3)
console.log(s.size); // 3

# Set 方法

add() 添加元素到集合

const s = new Set();
s.add(1)
s.add(2)
console.log(s); // Set(2) {1, 2}

delete() 删除元素

const s = new Set();
s.add(1)
s.delete(1)
console.log(s); // Set(0) {}

has() 检查集合中是否存在某个元素

const s = new Set();
s.add(1)
console.log(s.has(2)); // false

clear() 清空集合

const s = new Set();
s.add(1)
s.add(2)
s.add(3)
s.clear()
console.log(s); //  Set(0) {}

# WeakSet

WeakSet 他和 Set 有三点区别

    1. WeakSet 实例中只能存放对象
    1. WeakSet 中对元素的引用是弱引用。如果某个元素的引用计数为 0 时他将自动被垃圾回收机制回收 WeakSet 实例中也会自动消失。
    1. WeakSet 不能被遍历。由于垃圾回收机制不可预测,成 员都是弱引用,随时可能消失 遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。
const ws = new WeakSet();
ws.add(1);  //  Invalid value used in weak set
let a = {}
ws.add(a)
console.log(ws);

for (let i of ws) { // 此处报错:ws is not iterable
  console.log(i)
}
上次更新: 7/6/2020, 3:51:16 PM