Set是ES6中新的数据结构,它与数组类似,但是Set里面没有重复的值,可以用new运算符来构造一个Set,Set的构造函数可以传入一个参数,参数要是有iterable的结构,比如数组,arguments,字符串,元素集合,Set结构,Map结构等
let s1=new Set([1,2,3,4,5]);
let s2=new Set("abcdef");
Set有一个属性size,可以得到Set结构的value个数
let s1=new Set([1,2,3,4,5]);
let s2=new Set([1,2,3,4,5,5]);
console.log(s1.size+" "+s2.size);
//5 5
上面传入Set的两个数组长度不同,最后返回的size却是一样的,这是因为第二个数组里,5是重复的,所以并没有真的添加进去,所以长度也只有5。
但也有特殊的,比如传入两个{},size会变为2,这是因为Set内部判断两个值是否相等使用的算法类似于===,但有所不同的是在Set中,两个NaN是相同的,所以传入两个NaN后size为1,而因为"5"!==5,所以new Set(["5",5]}的size等于2
new Set([{},{}]).size//2
new Set([NaN,NaN]).size//1
new Set(["5",5]).size;//2
add(value)
add方法接受一个参数,如果Set结构中已有和参数相同的值,则不做操作,如果没有和参数相同的值,则将该值添加到Set中,最后返回操作后的Set,因此可以通过链式结构来添加多个值。
let s=new Set([1,2,3,4]);
console.log(s.size);//4
s.add(5);
console.log(s.size);//5
s.add(5);
console.log(s.size);//5
s.add(6).add(7).add(8);//返回的还是Set结构,所以可以继续调用add
console.log(s.size);//8
delete(value)
delete方法同样接受一个参数,如果Set结构中已有和参数相同的值,则删除该值,返回true,如果没有相同的值,则返回false,因为返回的是一个布尔值,所以不能使用链式结构删除多个值
let s=new Set([1,2,3,4,5]);
console.log(s.size);//5
s.delete(1);
console.log(s.size);//4
s.delete(1);
console.log(s.size);//4
has(value)
has方法用于判断该Set结构中是否有和参数相同的值,有的话返回true,没有的话返回false,无论有没有都不对数组进行操作。
let s=new Set([1,2,3,4]);
s.has(1);//true
s.has(6);//false
clear()
clear方法不用传入参数,会把整个Set结构清空
let s=new Set([1,2,3,4]);
console.log(s.size);//4
s.clear();
console.log(s.size);//0
keys()和values()
keys遍历键名,values遍历键值,但是因为Set没有键名,所以keys和values得到的结果是一样的
let s=new Set([1,2,3]);
for (let item of s.keys()) {
console.log(item);
}
//1 2 3
for (let item of s.values()) {
console.log(item);
}
//1 2 3
entries()
entries方法返回键名和键值,因为Set没有键名,所以就返回两个键值
let s=new Set([1,2,3]);
for (let item of s.entries()) {
console.log(item);
}
//[1, 1]
//[2, 2]
//[3, 3]
forEach()
Set结构的forEach方法和数组的forEach方法一样,参数依次为键名,键值,集合本身(这里为调用该方法的Set实例),因为没有键名,所以这里的键名依然和键值一样。
let s=new Set([1,2,3]);
s.forEach(function(key,val,set){
console.log(key+" "+val+" "+set);
})
//1 1 [object Set]
//4 2 2 [object Set]
//4 3 3 [object Set]
1.通过使用扩展运算符或者Array.from方法实现Set结构转化为数组
let s=new Set([1,2,3]);
console.log([...s]);//[1,2,3]
console.log(Array.from(s));//[1,2,3]
2.数组去重
将数组传入Set的构造函数中,再转化为数组,实现数组的去重
let arr=[1,2,3,3,4];
[...new Set(arr)]//[1,2,3,4]
3.实现交集,并集,差集
let arr1=[1,2,3,4];
let arr2=[1,3,5,7];
let union=[...new Set([...arr1,...arr2])];//并集
//[1,2,3,4,5,7]
let intersect = [...new Set(arr1.filter(x => new Set(arr2).has(x)))];//交集
//[1,3]
let dif = [...new Set(arr1.filter(x => !new Set(arr2).has(x)))];
//[2,4]
与Set结构类似,但是WeakSet的成员只能是对象,而且WeakSet中的对象都是弱引用,没有被垃圾回收机制考虑,如果WeakSet外部对该对象的引用消失,该对象会被垃圾回收机制回收,WeakSet中的该对象就会消失。
WeakSet有三个操作方法,add(value),delete(value),has(value),使用方法和Set中对应的这三个方法一样,但是要传入对象参数,WeakSet没有size属性和forEach,无法进行遍历。
let ws=new WeakSet([{1:2},{2:3}]);
在ES5的对象中,键名必须为字符串,否则会被自动转化为字符串,而通过使用Map,我们可以使用任意结构的键名,使用Map构造函数声明一个Map结构时,传入一个数组参数,数组里面是长度为2的多个数组,内层数组第一个值为键名,第二个值为键值,如果键名相同,那么后写入的会覆盖先写入的
let m=new Map([[1,2],[true,false],[{a:1},{b:2}],[[1,2,3],[4,5,6]]]);
let k1='111';
let k2='111';
let m1=new Map([[k1,1],[k2,2]]);
m1.get(k1)//1
m1.get(k2)//2
Map上的键实际上是跟内存地址绑定的,只要内存地址不同,就视为两个键,所以上面代码中虽然k1==k2,但是内存地址是不同的,所以视为两个键。
get(value)和set(value)
get方法传入一个参数,参数即为key,若Map中有对应的key的话就返回对应的value,没有的话返回undefined;set方法传入两个参数,第一个为key,第二个为value,如果Map中有对应的key,则修改对应的value,如果没有的就添加新的key和value,返回新得到的Map(可以使用链式结构多次添加)
let m=new Map([[1,"first"],[2,"second"]]);
m.get(1);//first
m.set(3,"third");
delete,has,clear的用法和Set的用法是一样的,delete和has通过键名来查找对应的值,如下代码
let m=new Map([[1,"first"],[2,"second"]]);
console.log(m.size);//2
m.delete(1);
console.log(m.size);//1
m.has(2);//true
console.log(m.size);//1
m.clear();
console.log(m.size)//0
forEach,values,keys,entries
forEach即遍历Map中对应的key和value
而values和keys顾名思义就是遍历Map中所有的value和key,使用for of来遍历
entries则同时遍历value和key,同时可以取得Map实例
const 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);
}
// "F" "no"
// "T" "yes"
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
1.Map转数组
使用扩展运算符
let m=new Map([[1,"first"],[2,"second"]]);
[...m]
2.数组转Map
直接将数组传入Map构造函数中
new Map([
[1, "first"],
[2, "second"]
])
3.Map转对象
如果Map中所有key都为字符串,则可以直接转为对象,如果有非字符串,则强制转为字符串再转为对象
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
const myMap = new Map()
.set('yes', true)
.set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
4.对象转Map
使用set方法将对应的key和value传入
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}
5.Map转为json
如果Map中的key都为字符串,那么转为对象json,如果有非字符串的key,则转为数组json
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
6.json转为Map
使用json.parse将json转为对象后,使用对象转Map的方法转为Map
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
WeakMap只接受对象作为键名(null除外),其他的类型作为键名都会报错
作为键名的对象不计入垃圾回收机制,是弱引用,与WeakSet的成员一样,如果外部的引用消失的话,该对象也会被清除,但要注意的是,只有键名是弱引用,键值并不是弱引用,键值仍会计入垃圾回收机制,如果外部引用消失,键值并不会消失。
参考自阮一峰的《ECMAScript6入门》
ES6学习笔记目录(持续更新中)
ES6学习笔记(一)let和const
ES6学习笔记(二)参数的默认值和rest参数
ES6学习笔记(三)箭头函数简化数组函数的使用
ES6学习笔记(四)解构赋值
ES6学习笔记(五)Set结构和Map结构
ES6学习笔记(六)Iterator接口
ES6学习笔记(七)数组的扩展
ES6学习笔记(八)字符串的扩展
ES6学习笔记(九)数值的扩展
ES6学习笔记(十)对象的扩展
ES6学习笔记(十一)Symbol
ES6学习笔记(十二)Proxy代理
ES6学习笔记(十三)Reflect对象
ES6学习笔记(十四)Promise对象
ES6学习笔记(十五)Generator函数
ES6学习笔记(十六)asnyc函数
ES6学习笔记(十七)类class
ES6学习笔记(十八)尾调用优化
ES6学习笔记(十九)正则的扩展
ES6学习笔记(二十)ES Module的语法