ES6学习笔记(三):Set和Map数据结构

Set的初始化

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

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

1
2
3
4
5
6
let set = new Set();
let arr = [1, 3, 4, 4, 5, 3, 2];
arr.map(x => set.add(x));
for(let value of set) {
console.log(set); // 1 3 4 5 2
}

上面的代码中Set通过实例的add方法来添加成员,结果表明Set不会添加重复的值。

除了使用add方法之外,Set还可以接受一个数组(或类似数组的对象)作为参数来初始化。

1
2
3
4
5
let set1 = new Set([1, 3, 3, 5, 4, 4]);
let arr = [...set1]; // [1, 3, 5, 4]
let divs = document.querySelectorAll('div');
let set2 = new Set(divs);
set2.size; // 10

去除数组重复成员的方法

1
2
let arr = [1, 3, 3, 5, 4, 4];
arr = [...new Set(arr)]; // [1, 3, 5, 4]

Set实例的属性和方法

(1)Set实例的属性:

属性名 说明
Set.prototype.constructor 构造函数,默认就是Set函数
Set.prototype.size 返回Set实例的成员总数

(2) Set实例的方法:
1、操作方法

方法名 说明
add(value) 添加一个值,返回Set结构本身
delete(value) 删除某个值,返回一个布尔值,表示删除是否成功
has(value) 判断某个值是不是Set的成员,返回一个布尔值
clear() 清除所有成员,没有返回值

操作方法使用示例

1
2
3
4
5
6
7
let set = new Set();
set.add(1).add(2);
set.has(1); // true
set.delete(1); // true
set.has(1); // false
set.clear();
set.size; // 0

2、遍历方法

方法名 说明
keys() 返回键名的遍历器
values() 返回键值的遍历器
entries() 返回键值对的遍历器
forEach(value, key) 使用回调函数遍历,参数顺序为值,键

遍历方法使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let set = new Set(['orange', 'apple', 'pear']);
// 使用keys遍历键名
for(let key of set.keys()) {
console.log(key); // orange apple pear
}
// 使用values遍历键值
for(let value of set.values()) {
console.log(value); // orange apple pear
}
// 使用entries遍历键值对
for(let item of set.entries()) {
console.log(item); // ["orange", "orange"] ["apple", "apple"] ["pear", "pear"]
}
// 或者
for(let [key, value] of set.entries()) {
console.log(key, value); // orange orange apple apple pear pear
}
// 使用forEach遍历
set.forEach((value, key) => {
console.log(key + ': ' + value); // orange: orange apple: apple pear: pear
});

通过上面代码中entires方法遍历的返回值可以看出,Set结构的键名和键值是相同的,所以对于Set结构来说keysvalues方法遍历是没有区别的。
Set结构的实例默认可遍历,它调用的默认遍历函数就是values方法。

1
Set.prototype[Symbol.iterator] === Set.prototype.values; // true

这意味着,可以省略values方法,直接使用for...of遍历Set结构。

1
2
3
4
let set = new Set(['orange', 'apple', 'pear']);
for(let value of set) {
console.log(value); // orange apple pear
}

Map的初始化

ES6新增了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。传统的Object结构提供了“字符串-值”的对应,而Map结构提供了“值-值”的对应,功能更加完善。

Map是一个构造函数,用来生成Map数据结构。

1
2
3
4
5
6
7
let map = new Map();
map.set(1, 1000); // 使用number当“键”
map.set('auth', '张三'); // 使用string当“键”
map.set(undefined, 'name'); // 使用undefined当“键”
map.set({'sex': '男'}, 1000); // 使用object当“键”
map.set(null, 1000); // 使用null当“键”
console.log(map); // {1 => 1000, "auth" => "张三", undefined => "name", Object {sex: "男"} => 1, null => 1000}

上面的代码中,使用set(key, value)方法为Map结构添加成员,而且这里的“键”可以是任何类型的值。
除了set方法之外,Map还可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组。

1
2
3
4
5
6
7
let arr = [['name', '张三'], ['age', 30], ['sex'], [10, 20, 30]];
let map = new Map(arr);
map.get('name'); // '张三'
map.get('age'); // 30
map.get('sex'); // undefined
map.get(10); // 20
console.log(map); // {"name" => "张三", "age" => 30, "sex" => undefined, 10 => 20}

Map接受数组作为参数,实际是执行的下面的操作。

1
2
3
4
5
let arr = [['name', '张三'], ['age', 30]];
let map = new Map();
arr.forEach(([key, value]) => {
map.set(key, value);
});

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

1
2
3
let map = new Map();
map.set('name', '张三').set('name', '李四');
map.get('name'); // '李四'

如果读取一个不存在的键,将返回undefined

1
2
let map = new Map();
map.get('name'); // undefined

注意:只有对同一个对象的引用,Map结构才将其视为同一个键,这一点要非常小心。

1
2
3
4
5
let map = new Map();
map.set({'a': 1}, 100);
map.get({'a': 1}); // undefined
map.set([1], 200);
map.get([1]); // undefined

上面的代码中,set和get中的键名是一样,但是实际上是两个值,因为内存地址是不一样的,所以get方法无法读取该键,返回undefined
要解决这种问题可以把键名是数组或对象的键用变量代替。

1
2
3
4
5
6
7
8
9
10
11
let map = new Map();
let a = [1];
let b = [1]
let o = {'a': 1};
map.set(a, 100);
map.get(a); // 100
map.set(b, 200);
map.get(b); // 200
map.set(o, 300);
map.get(o); // 300
console.log(map); // {[1] => 100, [1] => 200, Object {a: 1} => 200}

Map实例的属性和方法

(1)Map实例的属性:

属性名 说明
Map.prototype.constructor 构造函数,默认就是Map函数
Map.prototype.size 返回Map实例的成员总数

(2)Map实例的方法:
1、操作方法

方法名 说明
set(key, value) 设置key所对应的键值,返回Map结构本身
get(key) 读取key对应的键值,如果找不到key,返回undefined
delete(key) 删除key对应的键和值,返回一个布尔值,表示删除是否成功
has(key) 判断某个键是不是Map的成员,返回一个布尔值
clear() 清除所有成员,没有返回值

操作方法使用示例

1
2
3
4
5
6
7
let map = new Map();
map.set('a', 100).set('b', 200);
map.get('a'); // 100
map.delete('a'); // true
map.has('a'); // false
map.clear();
map.size; // 0

2、遍历方法

方法名 说明
keys() 返回键名的遍历器
values() 返回键值的遍历器
entries() 返回键值对的遍历器
forEach(value, key) 使用回调函数遍历,参数顺序为值,键

便利方法使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let map = new Map([['name', '张三'], ['age', 30], ['addr', '深圳'], ['sex']]);
// 使用keys遍历键名
for(let key of map.keys()) {
console.log(key); // name age addr sex
}
// 使用values遍历键值
for(let value of map.values()) {
console.log(value); // 张三 30 深圳 undefined
}
// 使用entries遍历键值对
for(let item of map.entries()) {
console.log(item); // ["name", "张三"] ["age", 30] ["addr", "深圳"] ["sex", undefined]
}
// 或者
for(let [key, value] of map.entries()) {
console.log(key, value); // name 张三 age 30 addr 深圳 sex undefined
}

Map结构的实例默认可遍历,它调用的默认遍历函数就是entries方法。

1
Map.prototype[Symbol.iterator] === Map.prototype.entries; // true

这意味着,可以省略entries方法,直接使用for...of遍历Map结构。

1
2
3
4
let map = new Map([['name', '张三'], ['age', 30], ['addr', '深圳'], ['sex']]);
for(let [key, value] of map) {
console.log(key, value); // name 张三 age 30 addr 深圳 sex undefined
}

Map的forEach方法和数组的类似,可以对每个成员执行某种操作。

1
2
3
4
let map = new Map([['a', 100], ['b', 200]]);
map.forEach((value, key) => {
console.log(key, value*2); // a 200 b 400
})

参考链接
ECMAScript 6 入门(阮一峰):Set和Map数据结构

坚持原创技术分享,您的支持将鼓励我继续创作!