ES6学习笔记(五)Set结构和Map结构

Set


  • Set的构建

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
  • Set的操作方法

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
  • Set的遍历方法

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]
  • 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]


  • WeakSet

与Set结构类似,但是WeakSet的成员只能是对象,而且WeakSet中的对象都是弱引用,没有被垃圾回收机制考虑,如果WeakSet外部对该对象的引用消失,该对象会被垃圾回收机制回收,WeakSet中的该对象就会消失。

WeakSet有三个操作方法,add(value),delete(value),has(value),使用方法和Set中对应的这三个方法一样,但是要传入对象参数,WeakSet没有size属性和forEach,无法进行遍历。

let ws=new WeakSet([{1:2},{2:3}]);

Map


  • Map的构造

在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,但是内存地址是不同的,所以视为两个键。

  • Map的操作方法

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
  • Map的遍历方法

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

WeakMap只接受对象作为键名(null除外),其他的类型作为键名都会报错

作为键名的对象不计入垃圾回收机制,是弱引用,与WeakSet的成员一样,如果外部的引用消失的话,该对象也会被清除,但要注意的是,只有键名是弱引用,键值并不是弱引用,键值仍会计入垃圾回收机制,如果外部引用消失,键值并不会消失。


参考自阮一峰的《ECMAScript6入门》

猜你喜欢

转载自blog.csdn.net/zemprogram/article/details/86310066