【读书笔记】ES6 第11章 Set 和 Map 数据结构

第11章 Set 和 Map 数据结构

参考资料:《ES6标准入门第3版》

目录

第11章 Set 和 Map 数据结构

11.1 Set 数据结构

11.1.1 基本用法

11.1.2 Set 实例的属性和方法

11.1.3 遍历操作

11.2 Map 结构

11.2.1 基本用法

11.2.2 Map 实例的属性和方法

11.2.3 Map 遍历方法

11.2.4 Map 与其他数据类型的转换


11.1 Set 数据结构

11.1.1 基本用法

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。相当于数学中的集合。

Set本身是一个构造函数,用来生成 Set 数据结构。

1. Set 结构不会添加重复的值。

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4

跟数组不一样,Set 实例通过 add() 方法添加成员,在添加成员的时候,若Set 结构中已经存在该值,则该成员不会被添加。

2. Set 函数可以接受一个数组作为参数来初始化

const set = new Set([1, 2, 3, 4, 4, 4, 4, 4]);

console.log([...set])
// [1, 2, 3, 4]

console.log(set.size)
// 4

访问 Set 数据结构的变量的大小只能通过 set.size 来访问,set.length 结果是 undefined

3. Set 数据结构中的类型判断

由于 Set 数据结构的特性,可以很方便地实现去除数组重复成员。

var array = [1, 2, 3, 3, 4, 4, 5, 5]
var newarray = [...new Set(array)]
console.log(newarray)
// [ 1, 2, 3, 4, 5 ]

这里有必要讨论下 Set 如何判断两个值是否相等。

Set 对加入的值不会发生类型转换,5 和 “5” 是两个不同的值。

const set = new Set()
set.add(5)
set.add('5')
console.log(set.size) // 2

Set 内部判断两个值的是否相同的方法类似于精确相等运算符( === ),不同的是在 Set 结构中 NaN 等于本身,而精确相等运算符认为 NaN 不等于本身。

console.log(NaN === NaN)
// false 

const set = new Set()
set.add(NaN)
set.add(NaN)
console.log(set.size)
// size = 1, 说明在 set 内部认为 NaN 相等,只添加了一个值

另外,无论对象是否为空,两个对象总是不相等。

const set = new Set()
set.add({})
set.add({})
console.log(set.size) // 2

11.1.2 Set 实例的属性和方法

Set 结构的实例有以下属性:

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

Set 结构有如下方法:

  • add(value):添加某个值,返回 Set 结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值

11.1.3 遍历操作

Set 结构的实例有四个遍历方法,可以用于遍历成员。

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

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

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

Set 结构的实例默认可遍历,可以省略values方法,直接用for...of循环遍历 Set。

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

for (let x of set) {
  console.log(x);
}
// red
// green
// blue

11.2 Map 结构

11.2.1 基本用法

ES6 提供了 Map 数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

const map = new Map();

const object = { 
	word: 'Hello World'
};

map.set(object, 'content')

console.log(map.get(object)) // "content"

console.log(map.has(object)) // true

map.delete(object) // true

console.log(map.has(object)) // false

上面的例子就是把一个对象当做 map 的一个键,把一个字符串 “content” 作为该对象键对应的值,map 可以正常读取、或删除这个键值对。

Map 结构除了可以使用 set 方法来添加成员,也可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组。

const items = [
	  ['name1', '张三'],
	  ['name2', '李四']
];

const map = new Map(items);

console.log(map.size)  // 2

console.log(map.has('name1')) // true

console.log(map.get('name1')) // 张三

如果对同一个键多次赋值,后面的值将会覆盖前面的值。

const map = new Map();

map
.set(1, 'aaa')
.set(1, 'bbb');

map.get(1) // "bbb"

读取一个未知的值返回 undefined。

new Map().get('abc') 
// undefined

注意点:

1. 只有对同一个对象的引用,Map 结构才将其视为同一个键。

const map = new Map();

let b = ['b']

map.set(['a'], 555)
map.get(['a']) // undefined

map.set(b, 666)
map.get(b) // 666

2. 如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键。

let map = new Map();

map.set(-0, 123);
map.get(+0) // 123

map.set(true, 1);
map.set('true', 2);
map.get(true) // 1

map.set(undefined, 3);
map.get(undefined) // 3

map.set(null, 4);
map.get(null) // 4


map.set(NaN, 123);
map.get(NaN) // 123

在上述代码的描述中,+0 与 -0 相等,同时 Map 将 NaN 视为同一个键,null 和 undefined 也被视为不同的键。

11.2.2 Map 实例的属性和方法

(1)size 属性 :size 属性返回 Map 结构的成员总数。

(2)set(key, value) :set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

set方法返回的是当前的Map对象,因此可以采用链式写法。

let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');

(3)get(key):get方法读取key对应的键值,如果找不到key,返回undefined

(4)has(key):has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

(5)delete(key):delete方法删除某个键,返回true。如果删除失败,返回false

(6)clear():clear方法清除所有成员,没有返回值。

11.2.3 Map 遍历方法

Map 结构原生提供三个遍历器生成函数和一个遍历方法。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。

需要特别注意的是,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"

11.2.4 Map 与其他数据类型的转换

1. Map 与数组的互相转换

Map 结构转换为数组结构的比较快速的方法是结合扩展运算符 (...)。

const map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

console.log([...map])
// [ [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ] ]

数据结构转为Map直接将数组作为参数传入Map构造函数就可以了,就如上述代码中的数组所示。

2. Map 与对象的互相转换

如果所有 Map 的键都是字符串,它可以无损地转为对象。

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }

如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名。

对象转为 Map,本质上就是遍历对象的所有属性,然后用 set 方法为 Map 结构添加成员。

function objToStrMap(obj) {
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    strMap.set(k, obj[k]);
  }
  return strMap;
}

objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}

 

你可能感兴趣的:(ECMAScript6,Set,Map)