Set、Map

174 阅读6分钟

Set

概念

  • 类似于数组,成员唯一(内部元素没有重复的值)。
  • Set 本身是一种构造函数,用来生成 Set数据结构。
  • Set 对象允许你储存任何类型的唯一值,无论是原始值或者是对象引用。

Set实例对象的方法:

  • add(value):添加某个值,返回 Set 结构本身(可以链式调用)。
  • delete(value):删除某个值,删除成功返回true,否则返回false。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。

Set实例对象的属性:

  • size:返回Set实例的成员总数

Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待:

  • +0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复
  • undefined 与 undefined 是恒等的,所以不重复
  • NaN 与 NaN 是不恒等的,但是在 Set 中认为NaN与NaN相等,所有只能存在一个,不重复。
  • {} {} 两个空对象的指针不一样,所以会重复
let a = undefined
let b = undefined
console.log(a==b,a===b)    
let c = NaN
let d = NaN
console.log(c==d,c===d)
let e = {}
let f = {}
console.log(e==f,e===f)
let g = +0
let h = -0
console.log(g==h,g===h)

let arr = [undefined, undefined, NaN, NaN, {}, {}, -0, +0];
console.log(new Set(arr))

image.png

应用

数组去重

var array = [0,1,1,2,2,5,5,66,99,65,65];
console.log(Array.from(new Set(array))); //Array(7) [0, 1, 2, 5, 66, 99, 65]
console.log([...new Set(array)]); //Array(7) [0, 1, 2, 5, 66, 99, 65]

数组的并集

let arr1 = [1,2,3];
let arr2 = [3,4,5];
let s1 = new Set([...arr1,...arr2]) //这样就把重复的3去掉了
console.log([...s1]);

数组的交集

let arr1 = [1,2,3,1];
let arr2 = [3,4,5,4];
let s1 = new Set(arr1);//先去除arr1数组自身的重复项
let s2 = new Set(arr2);//去除arr2数组自身的重复项
let arr = [...s1].filter((item)=>{
     return s2.has(item) //has方法看s2里有没有item这一项
})
console.log(arr)

数组的差集

let arr1 = [1,2,3,1];
let arr2 = [3,4,5,4];
let s1 = new Set(arr1);
let s2 = new Set(arr2);
let arr = [...s1].filter((item)=>{
     return !s2.has(item)
})
console.log(arr)

遍历Set

Array可以使用下标,Map和Set不能使用下标,ES6引入了iterable类型,Array,Map,Set都属于iterable类型(iterable内置forEach方法),它们可以使用for...of循环来遍历,意思为循环集合中的元素。

遍历方法
 keys():返回键名的遍历器。
 values():返回键值的遍历器。
 entries():返回键值对的遍历器。
 forEach():使用回调函数遍历每个成员。
 
由于Set结构没有键名,只有键值(**或者说键名和键值是同一个值**),所以keys方法和values方法的行为完全一致。

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

// 直接遍历set实例,等同于遍历set实例的values方法
for (let i of set) {
  console.log(i)
}
// a
// b
// c

set.forEach((value, key) => console.log(key + ' : ' + value))

// a: a
// b: b
// c: c

Map

概念

  • Map类似于对象,是键值对的集合,但是“键”的范围不限制于字符串,各种类型的值(包含对象)都可以当作键,可用于做数据储存。
  • 初始化Map需要一个二维数组,或者直接初始化一个空Map
  • Map里面也不可以放重复的项。

Map对象的属性:

  • size:返回Map对象中所包含的键值对个数

Map对象的方法:

  • set(key, val): 向Map中添加新元素
  • get(key): 通过键值查找特定的数值并返回
  • has(key): 判断Map对象中是否有Key所对应的值,有返回true,否则返回false
  • delete(key): 通过键值从Map中移除对应的数据
  • clear(): 将这个Map中的所有元素删除
let map = new Map([['js','react']]);
map.set('js','react');//看看是否可以放重复的项
map.set('javaScript','vue');
console.log(map) 

image.png

应用

遍历Map

遍历方法
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员

const map = new Map([['a', 11], ['b',  22]])

for (let key of map.keys()) {
  console.log(key)
}
// "a"
// "b"

for (let value of map.values()) {
  console.log(value)
}
// 11
// 22

for (let item of map.entries()) {
  console.log(item)
}
// ["a", 11]
// ["b", 22]

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value)
}
// "a" 11
// "b" 22

// for...of...遍历map等同于使用map.entries()

for (let [key, value] of map) {
  console.log(key, value)
}
// "a" 11
// "b" 22

Map与obj转换

  • Object.entries获取对象的键值对
  • Object.FromEntries把键值对列表转成对象
  • Object.entries和Object.fromEntries之间是可逆的。
Map转Obj
const obj = {}
const map = new Map(['a', 11], ['b', 22])
for(let [key,value] of map) {
  obj[key] = value
}
console.log(obj) 
// {a:11, b: 22}

let map=new Map([['foo','hello'],['bar',100]]);
let obj=Object.fromEntries(map);
console.log(obj);
Obj转Map
let obj={foo:'hello',bar:100};
let map=new Map(Object.entries(obj));
console.log(map)
// Map(2) {"foo" => "hello", "bar" => 100}

Array与Map转换

Array转Map
const arr = [{
	id: 1,
	goodNo: '1001'
  }, {
	id: 2,
	goodNo: '1002'
  }, {
	id: 3,
	goodNo: '1003'
  }]
  const map = new Map()
  arr.forEach(item => {
	map.set(item.id, item)
  })
  console.log(map)

image.png

Map转Array
var map = new Map();
map.set(1, "111");
map.set(2, "222");
map.set(3, "333");
console.log(map)
// map -> array
var arr = Array.from(map); // 二维数组
console.log(arr)
console.log(arr.flat());   // 压平(成为一维数组)
// (6) [1, "111", 2, "222", 3, "333"]

// 或:使用...rest运算符
console.log([...map]);  // 把map中的entries扩展为数组元素。

image.png

Map与Object

1.key的数据类型范围不同

  • Object:可以作为key的有:number,string,以及es6里面的symbol;
  • Map:js目前存在的数据类型均可以作为key;

2.key的顺序

  • Object: 如果对象的key中同时存在number string symbol 三种类型的时候,通过Object.keys得到的顺序是数字(升序) -> string(symbol)以创建的顺序;
  • Map: key以声明的顺序进行排序;

3.创建方式不同

  • Object:创建方式
    1. const obj1 = new Object()
    2. const obj2 = {}
    3. const obj3 = Object.create({})
  • Map:创建方式:
    1. const map = new Map();

4.key的调用方式不同

  • 通过key取值:
    1. Object:可通过 . 或 []
    2. Map:只能用原生的get方法进行调用;
  • 判断是否有某个属性
    1. Object:'a' in obj;判断obj中是否有a这个属性;
    2. Map:map.has('a');判断map中是否有a这个属性;

5.设置属性的方式不同

  • Object:
    1. obj.a = 1;
    2. obj['a'] = 1;
  • Map:js目前存在的数据类型均可以作为key;
    1. map.set('a',1)

6.删除key的方式

  • Object: 自身没有删除属性的方法;一般删除对象属性的方式: delete obj.a
  • Map: map.delete('a') ----删除a属性; map.clear() ----删除所有的属性;

7.获取size

  • Object: 通过Object.keys(obj) 返回一个数组,通过获取数组的长度来获取size;
  • Map: 自身带有size属性;map.size,size属性无法修改;

8.Iterating(迭代)

  • Object: 不可以
  • Map: 可以;

如何判断一个数据是否可以迭代的方式

  • typeof [][Symbol.iterator] //function
  • typeof new Map()[Symbol.iterator] //function
  • typeof {}[Symbol.iterator] //undefined
  • typeof 1[Symbol.iterator] //undefined

9.JSON操作

  • Object: 支持JSON.stringify和JSON.parse的操作;
  • Map: 不支持;

10.this不同

const f = function(){ console.log(this) }
Object: 
		const obj = {fn:f}
Map: 
		const map = new Map()
		map.set('fn',f)
		
obj.fn() //指向obj
map.get('fn')() //取决于函数的调用者;