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。