(四) Set和Map
1. Set
1.1 Set的基本使用
Set
是es6新增的引用类型的数据结构, 其本身也是一个构造函数, 可以接收一个数组作为参数
特点: 元素的值是唯一的, 不存在重复元素
基本使用
let set = new Set([1, 2, 2, 3, 1, 5])
console.log(set) // Set(4) {1, 2, 3, 5}
// 将Set转换成数组
let arr = [...set]
利用这一特性, 也为数组去重提供了新方法
let arr = [1, 2, 2, 3, 1, 5]
arr = [...new Set(arr)]
console.log(arr) // [1, 2, 3, 5]
此外, 我们还可以利用 Array.from()
将Set转换成数组
let set = new Set([1, 2, 3])
console.log(Array.from(set)) // [1,2,3]
那么Set保证内部元素不重复的机制是什么 ?
- 类似于
===
比较
注意这里说的是类似, 因为存在一个特殊的值 NaN
not a number
console.log(typeof NaN) // 'number'
console.log(NaN == NaN) // false
console.log(NaN === NaN) // false
NaN
与任何值都不相等, 包括它本身, 但是再Set中的判断却不是这样
console.log(new Set([NaN, NaN])) // Set(1) {NaN}
在Set内部, 将NaN和NaN当作是全等的
另外, 在Set内部, 像1 和 '1'
, {} 和 {}
都是不相等的 (遵循一般规则)
1.2 Set的实例属性和方法
属性: Set.prototype.size
返回实例的元素总数
let set = new Set([1, 2, 3, 4])
console.log(set.size) // 4
方法:分为操作方法和遍历方法
操作方法:
- add(value) : 添加值
- has(value): 判断是否有value这个元素, 返回布尔值
- delete(value): 删除值, 返回布尔值, 表示删除成功与否
- clear(): 清空
let set = new Set()
set.add(1).add(2)
console.log(set) // {1,2}
console.log(set.has(1)) // true
console.log(set.has(3)) // false
set.delete(2)
console.log(set) // {1}
set.clear()
console.log(set) // {}
遍历方法:
@注意: Set遍历的顺序是插入的顺序
- forEach(value, key, set)
- keys()
- values()
- entries()
let set = new Set([100, 200, 300])
set.forEach((v, k) => {
console.log(v, k);
})
/*
100 100
200 200
300 300
*/
// 值和键是相同的
1.3 案例
利用Set
和 ...
实现数组的 并集、交集、差集
let arr1 = [1, 2, 3]let arr2 = [4, 3, 2]// 并console.log(new Set([...arr1, ...arr2])) // {1,2,3,4}// 交let set1 = new Set(arr1)let set2 = new Set(arr2)console.log(new Set([...arr1].filter(item => set2.has(item)))) // {2,3}// 差console.log(new Set([...arr1].filter(item => !set2.has(item)))) // {1}
2. Map
2.1 Map的基本使用
Map
是es6新增的引用类型的数据结构, 其本身也是一个构造函数, 可以接收一个数组作为参数
- 参数数组的元素是 元素存在键值对映射关系的数组
基本使用
let map = new Map([['key', 'value']])console.log(map) // Map(1) {"key" => "value"}// 将Map转成数组let arr = [...map]
Map的出现解决了es5中对象的缺陷:
- 传统的Object提供的键值对组合, 键只能是 字符串, 而Map中的键允许是各种类型
// Objectlet obj = {}obj[{ id: 1 }] = 100console.log(obj) // {[object Object]: 100}// Maplet o1 = { a: 1 }let map = new Map()map.set(o1, '123')console.log(map) // Map(1) {{…} => "123"}console.log(map.get(o1)) // 123
可以利用 set(key, value) 为Map添加新成员
利用 get(key) 获取value
@注意:
- 与Object一样, 属性名相同的话, 后面的会覆盖前面的
- 但是, Map判断属性名是否相同是
根据内存地址是否相同
来作为依据的
let k1 = {}let k2 = k1 // k2定义为k1的引用let map = new Map([ [k1, 1], [k2, 2]])console.log(map) // Map(1) {{…} => 2} // 只存在一个成员, 却可以通过另外的属性名获取到值// 因为k2时是对k1的引用, 本质上还是对k1的查找console.log(map.get(k1)) // 2console.log(map.get(k2)) // 2
let k1 = {}let k2 = {}let map = new Map([ [k1, 1], [k2, 2]])console.log(map) // Map(2) {{…} => 1, {…} => 2}// 存在两个成员, 而且取到的值各不相同// 因为 {} 与 {} 是两个不同的对象 => 内存地址不同console.log(map.get(k1)) // 1console.log(map.get(k2)) // 2
2.2 Map的实例属性和方法
属性: size
属性, 返回实例的成员总数
操作方法:
- set(key,value) : 添加键值对, 如果key已经存在, 则更新覆盖
- get(key): 获取key对应的值
- has(key): 判断key是否在Map中, 返回一个布尔值
- delete(key)
- clear()
遍历方法:
@注意: Map遍历的顺序是插入的顺序
- forEach(value, key, set)
- keys()
- values()
- entries()
let map = new Map([ ['k1', 10], ['k2', 20]])map.forEach((value, key) => { console.log(value, key)})/* 10 "k1" 20 "k2"*/
仅记录自己的学习总结,如有错误,还请评论指正~