首页
ES6 Set 和 Map 数据结构的使用

ES6 提供了 SetMap 这两种数据结构,相比于之前的对象和数组,我们有了更多的选择。这篇文章主要讲解它们的使用方式以及一些好的实践。

Set

基本特性

  • 它类似于数组,但是成员的值都是唯一的,没有重复的值
  • Set 构造函数接收可迭代对象作为参数,用来初始化。
  • 向 Set 加入值时,使用的算法叫做Same-value-zero equality,它类似于精确相等运算符(===),不会发生类型转换。跟===唯一不一样的地方是,向它加入两个NAN认为是相等的。另外,两个对象总是不相等。
const set = new Set([5, '5', {}, {}, NaN, NaN])
console.log(set) // Set { 5, '5', {}, {}, NaN }

// 添加两个对象,是不同的元素
let set = new Set();
set.add({});
set.size // 1
set.add({});
set.size // 2

属性和方法

const mySet = new Set()
// add 添加元素
mySet.add(1)
mySet.add('jack')
// delete 删除元素
mySet.delete(1)
// 清空Set
mySet.clear()

方法都比较简单,主要注意一下entries,与数组不一样的是,返回的是一个[value, value]的可迭代对象。

//entries 返回一个迭代器对象,[value, value]
const setIter = set.entries()
for (let [value] of setIter) {
  console.log(value)
}

扩展运算符(...)内部使用for...of循环,所以也可以用于 Set 结构。

let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']

Array.from方法可以将 Set 结构转为数组。

const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);

最佳实践

// 去除数组的重复成员
[...new Set(array)]

// 去除重复字符
[...new Set('ababbc')].join('')


Map

基本特性

Map相比于Set来说,使用地更加频繁一些。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串 — 值”的对应,Map 结构提供了“值 — 值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

map 键的比较是基于sameValueZero 算法:NaNNaN是相等的,其他的都是类似===

map 与 object 的比较

属性和方法

map 的构造函数需要注意一下,它接收的是一个键值对类型的可迭代对象
例如: [[ 1, 'one' ],[ 2, 'two' ]])。 每个键值对都会添加到新的 Map

数组转 Map

const arr = [
  [true, 7],
  ['name', 'jack'],
]
const map1 = new Map(arr)
console.log(map1) //  Map { true => 7, 'name' => 'jack' }

对象转map

const person = {
  name: 'jack',
  age: 18,
  sex: 'male',
}

const map2 = new Map(Object.entries(person))
console.log(map2) //  Map { 'name' => 'jack', 'age' => 18, 'sex' => 'male' }

Json转map

function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')

map的遍历

const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);

for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.values()) {
  console.log(value);
}
// "no"
// "yes"

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

// 等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

最佳实践

  1. 使用 Map 替代 switch

switch

function animalSpeak(animalType) {
    switch (animalType) {
        case 'dog':
            console.log('Wang!');
            break;
        case 'cat':
            console.log('Miaow!');
            break;
        case 'bird':
            console.log('Jiu!');
            break
    }
}
animalSpeak('dog');

Map

const animalSpeak = {
    dog: ()=>console.log('Wang!'),
    cat: ()=>console.log('Miaow!'),
    bird: ()=>console.log('Jiu!'),
};
animalSpeak['dog']();

2. 作为hash

const number = [1, 2, 3]
const map = new Map(number.map((item, index) => [item, index]))
console.log(map)
// Map { 1 => 0, 2 => 1, 3 => 2 }

WeakSet 与 WeakMap

WeakSetSet的两个区别:

  1. 成员只能是对象,而不能是其他类型的值;
  2. WeakSet 里面的引用,都不计入垃圾回收机制

WeakMapMap的两个区别:

  1. WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为
  2. WeakMap的键名所指向的对象,不计入垃圾回收机制。