上一次我们一起重温了JS中数组相关的内容,这一次我们要来学习ES6新引入的两个数据结构:map和set。map和对象比较像,可以用键来获取值,set则和数组比较像,但是不允许出现重复的值。下面我们就进入详细地学习吧:
1.map
1.1 map和对象的比较
在mao没有诞生以前,要把键和值映射起来的时候,一般都会首选对象。对象能把字符串类型的键映射到任意类型的值。但是这样使用起来还是存在着问题:
1.对象有原型,对象原型中可能存在并不需要的映射;原型上的键名可能和你设置的键名冲突。
2.一个对象的键是无序的,对象不能保证自身属性的顺序。
3.对象中键的个数只能手动计算,所以弄清楚对象中有多少映射比较麻烦。
4.对象的键只能是字符串,这样一来就不能将对象映射到值。
map则解决了这些问题,它是将键和值映射起来的最佳选择,这是因为:
1.map默认情况不包含任何键,只包含显式插入的键。
2.map中的键是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。
3.map 的键值对个数可以轻易地通过size 属性获取。
4.map的键可以是任意值,包括函数、对象或任意基本类型。
下面通过实例看一下map的使用:
1.2 map的使用
1.2.1 设置值与取值
可以使用set()方法为map添加键值对,使用get()方法读取相应键所对应的值,使用size属性返回map中元素的个数:
let map = new Map()
let keyObj = {}
let keyFunc = function() {}
let keyString = 'string'
map.set(keyObj,'keyObjValue')
map.set(keyFunc,'keyFuncValue')
map.set(keyString,'keyStringValue')
console.log(map.size)
//3
console.log(map.get(keyObj))
//keyObjValue
console.log(map.get(keyFunc))
// keyFuncValue
console.log(map.get(keyString))
// keyStringValue
通过上例我们可以看到对象、函数、字符串都可以作为map的键。
可以链式地调用set()方法;当用一个map不存在的key调用get()方法时,就会返回一个undefined;如果key在ma p中已经存在,那么调用set()后key对应的value就会被替换:
map.set('key1','value1')
.set('key2','value2')
.set('key3','value3')
console.log(map.size)
// 6
console.log(map.get('key4'))
// undefined
map.set('key3','value33')
console.log(map.get('key3'))
// value33
1.2.2 迭代
使用keys()方法可以拿到map中所有的键;values()可以拿到所有的值;entries()可以以数组的方式获取键值对,数组的第一个元素为键,第二个元素为值;:
console.log(map.keys())
console.log(map.values())
console.log(map.entries())
运行结果如下图所示:
可以使用for…of循环来迭代:
for(let key of map.keys()) {
console.log(key)
}
运行结果如下图:
for(let value of map.values()) {
console.log(value)
}
运行结果如下图:
也可以使用forEach()方法来循环迭代:
for(let [key,value] of map) {
console.log(key,value)
}
map.forEach((value,key) => {
console.log(value,key)
})
1.2.3 删除和清除
可以使用delete方法删除map中的数据,可以使用clear()方法清除map中的数据:
map.delete('key3')
console.log(map.get('key3'))
// undefined
console.log(map.size)
// 5
map.clear()
console.log(map.size)
// 0
1.2.4 map和数组的转换
可以使用Map构造函数传入由键值对数组组成的数组(二维数组)构造map。而使用Array.from可以将map转换为数组,或者使用展开运算符…
//从数组构造map
let arr = [['key1','value1'],['key2','value2']]
let arrMap = new Map(arr)
console.log(arrMap.get('key1'))
// value1
//从map构造数组
let arr2 = Array.from(arrMap)
console.log(arr2)
let arr3 = [...arrMap]
console.log(arr3)
1.2.5 map的克隆和合并
可以将一个map传入Map构造函数从而创建另外一个map,即实现复制功能,但是这种复制是只复制数据的浅复制:
// 复制map
let mapOne = new Map([[1,'one']])
let clone = new Map(mapOne)
console.log(clone.get(1))
// one
console.log(clone === mapOne)
// false
可以将多个map合并,合并的方法是在一个数组中将多个map展开,然后这个数组作为参数传给Map构造函数:
// map的合并
let mapTwo = new Map([[1,'1'],[2,'two']])
let merged = new Map([...mapOne,...mapTwo])
console.log(merged)
// Map对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的
2.set
set是一个不允许重复的数据的集合,允许你存储任何类型的唯一值,无论是原始类型还是引用类型。
2.1 添加元素
我们看一下使用set的例子:
let set = new Set();
set.add(1);
set.add(2);
console.log(set);
//Set(2) {1, 2}
set.add(2);
console.log(set)
//Set(2) {1, 2}
set.add('new');
set.add({name: 'name'});
console.log(set)
// Set(4) {1, 2, "new", {…}}
console.log(set.size);
//4
如上代码使用Set的构造方法新建了一个set:new Set();然后向set中添加了2个不同的元素1和2;接着又向set中添加元素2时,由于set中已经存在2,所以添加失败;接着向set中添加字符串和对象;使用size属性可以查看当前size的元素个数。
2.2 删除元素
可以使用delete方法删除set中的元素,如果删除成功则返回true;如果删除一个set中不存在的元素将返回false;可以使用has方法判断元素是否在set中。
let res = set.delete(2)
console.log(res)
// true
console.log(set.has(2))
//false
res = set.delete(2)
console.log(res)
//false
2.3 迭代
可以使用for… of迭代set中的元素;set的键和值是相等,所以set.keys() ,set.values()得到的结果是一样的,set.entries() 得到的每个元素都是一个数组,其中是两个一样的元素。看一下代码:
for(let item of set) {
console.log(item)
//1
//new
//{name: "name"}
}
for(let item of set.keys()) {
console.log(item)
//1
//new
//{name: "name"}
}
for(let item of set.values()) {
console.log(item)
//1
//new
//{name: "name"}
}
for(let item of set.entries()) {
console.log(item)
// [1, 1]
// ["new", "new"]
// [{name: "name"},{name: "name"}]
}
2.4 和数组的转换
使用Array.from方法可以把Set转换为数组;在调用Set构造方法时可以传入一个数组就可以得到Set。如下代码所示:
let arr = Array.from(set);
console.log(arr);
// [1, "new",{name: "name"}]
set = new Set([1,2,3,3,4])
console.log(set)
// {1, 2, 3, 4}
另外也可以通过…运算符的方法,将Set转换为数组:
arr = [...set]
console.log(arr)
// [1, 2, 3, 4]
2.5 Set的集合运算
首次看一下求交集的例子:
let set1 = new Set([1,2,3]);
let set2 = new Set([2,3,4]);
// 求交集
function intersection(set1, set2) {
return new Set([...set1].filter(x => set2.has(x)))
}
let resSet = intersection(set1,set2);
console.log(resSet);
// Set(2) {2, 3}
再看一下求差集的例子:
let set1 = new Set([1,2,3]);
let set2 = new Set([2,3,4]);
function difference(set1, set2) {
return new Set([...set1].filter(x => !set2.has(x)));
}
resSet = difference(set1,set2);
console.log(resSet);
// Set(1) {1}
当然你也可以使用如下的方法求Set集合的差集:
function difference(setA, setB) {
let _difference = new Set(setA);
for (let elem of setB) {
_difference.delete(elem);
}
return _difference;
}
再看一下是否是子集的例子:
function isSuperset(set, subset) {
for (let elem of subset) {
if (!set.has(elem)) {
return false;
}
}
return true;
}
set1 = new Set([1,2,3])
set2 = new Set([2,3])
console.log(isSuperset(set1,set2));
//true
再看一下求并集的例子:
function union(setA, setB) {
let _union = new Set(setA);
for (let elem of setB) {
_union.add(elem);
}
return _union;
}
set1 = new Set([1,2,3])
set2 = new Set([3,4,5])
console.log(union(set1,set2))
// Set(5) {1, 2, 3, 4, 5}
最后看一下求交集的例子:
function intersection(setA, setB) {
let _intersection = new Set();
for (let elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem);
}
}
return _intersection;
}
set1 = new Set([1,2,3])
set2 = new Set([3,4,5])
console.log(intersection(set1,set2))
// Set(1) {3}
以上就是今天我们重温JS全部的内容,我们以一张导图来回顾一下今天的内容:
我们这次的分享就到这里,下次再会。如有错误,请不吝指正。温故而知新,欢迎和我一起重温旧知识,攀登新台阶~