ES6 提供了新的数据结构 Set
。它相似于数组,可是成员的值都是惟一的,没有重复的值。
Set
自己是一个构造函数,用来生成 Set 数据结构。数组
const setArr = new Set();
[1,2,3,4,2,2,3,4].forEach(x => setArr.add(x));
for (let i of setArr) {
console.log(i);
}
// 1,2,3,4
复制代码
Set
函数能够接受一个数组(或者具备 iterable
接口的其余数据结构)做为参数,用来初始化。 特色:bash
Set
加入值的时候,不会发生类型转换,因此4和"4"是两个不一样的值。// 以数组为参数
const set = new Set([1, 2, 3, 4, 4, '4'])
[...set] // [1, 2, 3, 4, '4']
set.size // 5
// 一个相似数组的带 iterable 接口的对象
const set = new Set(document.querySelectorAll('div'))
复制代码
将Set
结构转换成数组有两个简单的方法数据结构
[...set] // [1, 2, 3, 4, '4']
Array.from(set) // [1, 2, 3, 4, '4']
复制代码
Set
结构的实例有如下属性。函数
Set.prototype.constructor
:构造函数,默认就是Set
函数。Set.prototype.size
:返回Set
实例的成员总数。Set
实例的方法分为两大类:操做方法(用于操做数据)和遍历方法(用于遍历成员)。ui
add(value)
:添加某个值,返回 Set
结构自己。delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。has(value)
:返回一个布尔值,表示该值是否为Set
的成员。clear()
:清除全部成员,没有返回值。const s = new Set()
s.add(1).add(2).add(2)
s.size // 2
s.has(1) // true
s.has(2) // true
s.has(3) // false
s.delete(2)
s.size // 1
s.has(2) // false
复制代码
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每一个成员keys
方法、values
方法、entries
方法返回的都是遍历器对象。因为 Set
结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys
方法和values
方法的行为彻底一致。this
const set = new Set(['a', 'b', 'c']);
for (let item of set.keys()) {
console.log(item);
}
// a
// b
// c
for (let item of set.values()) {
console.log(item);
}
// a
// b
// c
for (let item of set.entries()) {
console.log(item);
}
// ["a", "a"]
// ["b", "b"]
// ["c", "c"]
复制代码
对象结构 在使用这个几个方法的时候相似,但有必定区别spa
const obj = { 1: 'a', 2: 'b', 3: 'c' }
for (let item of Object.keys(obj)) {
console.log(item);
}
// 1
// 2
// 3
for (let item of Object.values(obj)) {
console.log(item);
}
// a
// b
// c
for (let item of Object.entries(obj)) {
console.log(item);
}
// [1, "a"]
// [2, "b"]
// [3, "c"]
复制代码
Set
结构的实例默承认遍历,它的默认遍历器生成函数就是它的values
方法。
这意味着,能够省略values
方法,直接用for...of
循环遍历 Set
。prototype
for (let i of set) {
console.log(i)
}
// a
// b
// c
复制代码
forEach()
: Set 结构的实例与数组同样,也拥有forEach方法,用于对每一个成员执行某种操做,没有返回值。
不过key
和value
是同一个code
set.forEach((value, key) => console.log(key + ' : ' + value))
// a: a
// b: b
// c: c
复制代码
遍历的应用对象
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// 差集
let difference = new Set([...union].filter(x => !intersect.has(x)));
// Set {1}
复制代码
若是想在遍历操做中,同步改变原来的 Set 结构,目前没有直接的方法,但有两种变通方法。
// 方法一
let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
// set的值是2, 4, 6
// 方法二
let set = new Set([1, 2, 3]);
set = new Set(Array.from(set, val => val * 2));
// set的值是2, 4, 6
复制代码
WeakSet 结构与 Set 相似,也是不重复的值的集合。可是,它与 Set 有两个区别。
(1):WeakSet 能够接受数组和相似数组的对象做为参数。该数组的全部成员都会自动成为WeakSet的实例对象的成员。数组成员只能是对象,不能是其余类型的值。不然报错。
const a = [[1, 2], [3, 4], {a: 1}]
const ws = new WeakSet(a)
// WeakSet {[1, 2], [3, 4]}
const b = [1, 2, [1,2]]
new WeakSet(b) // Uncaught TypeError: Invalid value used in weak set
复制代码
(2):WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,若是其余对象都再也不引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
一个常规的对象本质应该是键值对的合集(即Hash结构)。它的键应该是一个字符串。 可是有时候须要使用其余类型好比对象来作 键值对的 键。 因而就有了Map
结构
const data = {};
const element = document.getElementsByTagName('div')
data[element] = 'div';
data[element] // "div"
data['[object HTMLCollection]'] // "div"
// {[object HTMLCollection]: "div"}
const elementSpan = document.getElementsByTagName('span')
data[elementSpan] // "div"
复制代码
element
被转化成了'[object HTMLCollection]'
只是个字符串。 并不能达到经过element
取到值的效果。可是,使用Map
结构能够。 Map
结构与对象很类似也是键值对, 但Map
的键能够不是字符串,能够是各类类型的值(包括对象)。若是你须要“键值对”的数据结构,Map
比 Object
更合适。
const dataMap = new Map()
dataMap.set(element, 'div')
dataMap.get(element) // div
// has,delete
dataMap.has(element) // true
dataMap.delete(element) // true
dataMap.has(element) // false
复制代码
以上 new Map()
实例对象为一个Map
结构,提供了set
、get
、has
、delete
几个方法。轻松了实现了增删改查。 构造函数Map
能够接受一个数组做为参数。
const map = new Map([ ['key1', 'value1'], ['key2', 'value2'] ])
复制代码
任何具备 Iterator 接口、且每一个成员都是一个双元素的数组的数据结构均可以看成Map构造函数的参数。如:数组,Set
结构, Map
结构。
const set = new Set([['a', 1],['b', 2]]);
const m1 = new Map(set);
m1.get('a') // 1
const m2 = new Map([['c', 3]]);
const m3 = new Map(m2);
m3.get('c') // 3
复制代码
注意:只有对同一个对象的引用,Map 结构才将其视为同一个键。
const k1 = {a: 1 }
const k2 = {a: 1 }
const map = new Map()
map.set(k1, 111)
map.get(k2) // undefined
map.set(k2, 222)
map.get(k1) // 111
map.get(k2) // 222
复制代码
由于即使值相同,可是两个对象内存地址是不同的。
若是 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,好比0和-0就是一个键。
set
方法设置键名key对应的键值为value
,而后返回整个 Map
结构。若是key
已经有值,则键值会被更新,不然就新生成该键。get
方法读取key
对应的键值,若是找不到key
,返回undefined
。Map
结构的成员总数。has
方法返回一个布尔值,表示某个键是否在当前 Map
对象之中。delete
方法删除某个键,返回true
。若是删除失败,返回false
。clear
方法清除全部成员,没有返回值。const map = new Map();
// 能够采用链式写法。
map.set('a', 1).set('b', 2)
map.size // 2
map.get('b') // 2
map.set('b', 222)
map.get('b') // 222
map.get('c') // undefined
map.has('b') // true
map.delete('b') // true
map.has('b') // false
map.clear()
map.size // 0
复制代码
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每一个成员须要特别注意的是,Map 的遍历顺序就是插入顺序。
const map = new Map([['a', 1], ['b', 2]]);
for (let key of map.keys()) {
console.log(key);
}
// "a"
// "b"
for (let value of map.values()) {
console.log(value);
}
// 1
// 2
for (let item of map.entries()) {
console.log(item);
}
// ["a", 1]
// ["b", 2]
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "a" 1
// "b" 2
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "a" 1
// "b" 2
复制代码
(1)Map 与数组的互换
const arr1 = [[{'k1': 11}, 11 ],['a', 1]]
const map = new Map(arr1)
[...map] // [[{'k1': 11}, 11 ],['a', 1]]
Array.from(map) // [[{'k1': 11}, 11 ],['a', 1]]
复制代码
(2) Map 与对象的互换
若是全部 Map 的键都是字符串,它能够转为对象。
const obj1 = { a:1, b:2 }
const obj2 = {}
const map = new Map()
for(let key of Object.keys(obj1)) {
map.set(key, obj1[key])
}
console.log(map) // Map(2) {"a" => 1, "b" => 2}
for (let [key,value] of map) {
obj2[key] = value
}
console.log(obj2) // {a: 1, b: 2}
复制代码
(3) JSON 要转换成 Map 能够先转换成数组或者对象,而后再转换。
WeakMap
结构与Map
结构相似,也是用于生成键值对的集合。
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);
wm2.get(k2) // "bar"
复制代码
const map = new WeakMap();
map.set(1, 2)
// TypeError: 1 is not an object!
复制代码
WeakMap
与 Map
类似但有两个区别:
WeakMap 应用的典型场合就是 DOM 节点做为键名。 WeakMap 的另外一个用处是部署私有属性。
const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);
_action.set(this, action);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
const c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
复制代码
习题: 一· 求set 的值
let arr1 = [1, 2, 3, '3', 2]
const set = new Set(arr1)
复制代码
二. 求遍历的输出
for (let [key, value] of set.entries()) {
console.log(key === value)
}
复制代码
三. set 转换数成数组
四. 求 data[obj1],
const obj1 = { a: 1}
const obj2 = { b: 2}
const data = {}
data[obj1] = 11
data[obj2] = 22
// 求 data[obj1]
复制代码
五. 1.求 map.get({a: 1}), 2.若是 map 要转换成其余结果,应该是对象仍是数组
const map = new Map()
map.set({a: 1}, 111)
map.get({a: 1})
复制代码