ES6 学习笔记 -- Set和Map数据结构

Set

创建Set数据结构

>// 两种方式
>let list = new Set();
>
>或者
>
>let array = [1, 2, 2, 4, 5];
>let list = new Set(array);
>
>let list = new Set( [1, 2, 2, 4, 5]);
>

基本用法

ES6 提供了新的数据结构 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
>

上面代码通过add()方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。根据这个性质,我们也可以使其与扩展运算符(…)相结合进行去重操作。

>// 去除数组的重复成员
>[...new Set(array)]
>
>// 去除字符串里面的重复字符
>[...new Set('ababbc')].join('')
>// "abc"
>

特别注意的是:向Set加入值的时候,不会发生类型转换。这意味着,在Set中5和”5”是两个不同的值。Set 内部判断两个值是否不同的方法类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。

>let set = new Set();
>let a = NaN;
>let b = NaN;
>set.add(a);
>set.add(b);
>console.log(set) // Set(1){NaN}
>
>// 结果表明只加入了一个NaN,这表明,在 Set 内部,两个NaN是相等。
>

set的属性和方法

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

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

Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

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

以上实例如下:

>let array = [1, 2, 2, 4, 5];
>let list = new Set(array);
>console.log(list.size);
>// 4
>
>list.clear();
>console.log('list',list);
>// list Set(0) {}
>
>list.add('add').add('delete').add('has');
>console.log('list',list);
>// list Set(3) {"add", "delete", "has"}
>
>console.log('delete',list.delete('add'),list);
>// delete true Set(3) {"delete", "has"}
>
>console.log('has',list.has('has'));
>// has true
>

注意: Array.from方法可以将Set结构转换为数组,这也提供了一种除去数组中重复元素的方法。

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

Set最常用也是最常问的问题就是 数组去重

遍历方法

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

以上是Set数据结构的四种遍历方法,运用比较简单,实例如下:

>let arr=['add','delete','clear','has'];
>let list=new Set(arr);
>
>for(let key of list.keys()){
> console.log('keys',key);
>}
>
>// keys add
>// keys delete
>// keys clear
>// keys has
>
>for(let value of list.values()){
> console.log('value',value);
>}
>
>// keys add
>// keys delete
>// keys clear
>// keys has
>
>for(let [key,value] of list.entries()){
> console.log('entries',key,value);
>}
>
>// entries add add
>// entries delete delete
>// entries clear clear
>// entries has has
>
>list.forEach(function(item){console.log(item);})
>// add
>// delete
>// clear
>// has
>

通过上面的示例结果可知,Set结构的key和value是一致的。

需要特别指出的是,Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。

Map

在ES5中,对象的键值对中键只能使用字符串,这就带来了很大的限制。

>var data = {};
>var element = document.getElementById("myDiv");
>
>// 将DOM节点(即element)当做对象data的键.
>// 但是对象只接受字符串作为键名,所以element被自动转换为字符串"[Object HTMLDivElement]"
>data[element] = metadata;
>

在ES6中增加了Map的数据结构,它类似于对象,但是键的范围不仅仅是字符串,而是各种类型的值都可以当做键。

>var m = new Map();
>o = {p: "hello world"};
>
>m.set(o, "content");
>console.log( m.get(o) ); // content
>

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

>const map = new Map();
>
>map.set(['a'], 555);
>map.get(['a']) // undefined
>

上面代码的set和get方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get方法无法读取该键,返回undefined。

同理,同样的值的两个实例,在 Map 结构中被视为两个键。

>const map = new Map();
>
>const k1 = ['a'];
>const k2 = ['a'];
>
>map
>.set(k1, 111)
>.set(k2, 222);
>
>map.get(k1) // 111
>map.get(k2) // 222
>

上面代码中,变量k1和k2的值是一样的,但是它们在 Map 结构中被视为两个键。

Map的属性和操作方法

- size : 返回成员总数。 
- set(key, value) : 设置一个键值对。 
- get(key) : 读取一个键。 
- has(key) : 返回一个布尔值,表示某个键是否在Map结构中。 
- delete(key) : 删除某个键。 
- clear() : 清除所有成员。

size属性

>let map = new Map();
>map.set('foo', true);
>map.set('bar', false);
>
>map.size // 2
>set(key, value)
>var m = new Map();
>
>m.set("edition", 6) // 键是字符串
>m.set(262, "standard") // 键是数值
>m.set(undefined, "nah")
>
>get(key)
>var m = new Map();
>
>var hello = function() {console.log("hello");}
>m.set(hello, "Hello ES6!") // 键是函数
>
>m.get(hello) // Hello ES6!
>
>has(key)
>var m = new Map();
>
>m.set("edition", 6);
>m.set(262, "standard");
>m.set(undefined, "nah");
>
>m.has("edition") // true
>m.has("years") // false
>m.has(262) // true
>m.has(undefined) // true
>delete(key)
>var m = new Map();
>m.set(undefined, "nah");
>m.has(undefined) // true
>
>m.delete(undefined)
>m.has(undefined) // false
>clear()
>let map = new Map();
>map.set('foo', true);
>map.set('bar', false);
>
>map.size // 2
>map.clear()
>map.size // 0
>

遍历方法

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

Map结构的遍历基本和Set结构是一样的,实例基本一样。

>let 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);
>}
>
>// 等同于使用map.entries()
>for (let [key, value] of map) {
> console.log(key, value);
>}
>
>

特别需要说明的是:forEach方法还可接受第二个参数,用来绑定this。

>var reporter = {
> report: function(key, value) {
> console.log("key: %s, Value: %s", key, value);
> }
>};
>
>map.forEach(function(value, key, map) {
> this.report(key, value)
>}, reporter);
>

上面代码中,forEach()方法的回调函数中的this, 就指向reporter。

Author: ahuiyoのblog
Link: http://ahuiyo.cn/ES6-学习笔记-Set和Map数据结构/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
支付宝打赏
微信打赏