浅谈JS的映射和集合

简介: 浅谈JS的映射和集合

引言

Map(映射)和Set(集合)是ES6引入的数据结构,它们提供了更灵活、高效的方式来存储和访问数据。本文将介绍一下这两种数据结构以及WeakMap(弱映射)和WeakSet(弱集合)这两种新的数据结构的概念及使用。

Map

Map是一种以键值对的形式存储数据的集合。它的结构类似于对象,它也是键值对的集合,但是Map的键可以是任何类型的值,包括对象、函数和原始类型等。可以说Map就是对象的一种扩展。

特点

  1. 键是唯一的,后添加的键值对会替换前面的
  2. 键值是有序的,使用Map对象将按照插入顺序得到每一个键值对
  3. 各种类型的值都可以当作键

属性及方法

创建

我们可以通过下面的代码创建一个空的Map

const map = new Map()
console.log(map); // Map(0) {}

赋予初始值:map使用 [ ] 表示层级结构,第一维度是映射的个数,第二维度是具体的值,结构是 [key, value]

const map = new Map<string, string | number>([['name', '阿黄'], ['age', 20]])
console.log(map); // Map(2) { 'name' => '阿黄', 'age' => 20 }

新增

通过set(key, value)来增加一个键值对,如果键已存在,则会更新对应的值

const map = new Map()
map.set('name', '阿黄')
console.log(map);// Map(1) { 'name' => '阿黄' }
map.set('name', '小黑')
console.log(map);// Map(1) { 'name' => '小黑' }

获取

使用get(key)返回key对应的值,如果值不存在则返回undefined

const map = new Map()
console.log(map.get('name')); // undefined
map.set('name', '阿黄')
console.log(map.get('name')); // 阿黄

是否存在值

使用map.has(key)可以判断是否存在键对应值

const map = new Map()
console.log(map.has('name')); // false
map.set('name', '阿黄')
console.log(map.has('name')); // true

删除

通过delete(key)来删除map的值

const map = new Map()
map.set('name', '阿黄')
console.log(map); // Map(1) { 'name' => '阿黄' }
map.delete('name')
console.log(map); // Map(0) {}

清空

使用map.clear()函数清空map

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
console.log(map); // Map(2) { 'name' => '阿黄', 'age' => 12 }
map.clear()
console.log(map); // Map(0) {}

获取长度

map可以通过size获取子集个数

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
console.log(map.size); // 2

键的迭代器

使用keys函数可以返回Map中所有的键的迭代器

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
console.log(map.keys()); // { 'name', 'age' }

值的迭代器

和keys类似,values函数可以返回Map中所有的值的迭代器

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
console.log(map.keys()); // { 'name', 'age' }

键值对的迭代器

使用entries或者是Symbol.iterator函数可以返回Map的键值对

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
console.log(map.entries()); // { [ 'name', '阿黄' ], [ 'age', 12 ] }
console.log(map[Symbol.iterator]()); // { [ 'name', '阿黄' ], [ 'age', 12 ] }

遍历

使用forEach函数进行遍历,和数组的forEach类似(数组第二项是索引),callback函数返回三个值,分别是value,key,map

const map = new Map()
map.set('name', '阿黄')
map.set('age', 12)
map.forEach((val, key, map) => {
    console.log(val, key, map);
})
// 阿黄 name Map(2) { 'name' => '阿黄', 'age' => 12 }
// 12 age Map(2) { 'name' => '阿黄', 'age' => 12 }

使用场景

描述映射关系

在对象中我们只能使用string或symbol来描述键的值,而Map可以很好的描述关系映射

const map = new Map()
map.set(['meat', 'fish'], '都是阿黄爱吃的')
console.log(map); // Map(1) { [ 'meat', 'fish' ] => '都是阿黄爱吃的' }

缓存

我们使用Map的索引唯一性特点将其运用于缓存操作,下面的代码中我们使用一个函数作为map的键,第一次调用函数会触发set操作,后续操作会直接使用get获取对应值

const cache = new Map();
const temp = (key: any) => cache.get(key) ?? (cache.set(key, getNum(1, 2)), cache.get(key))// 缓存操作,首次访问会执行set操作
const getNum = (a: number, b: number) => a + b
console.log(temp(getNum))
console.log(temp(getNum))

Set

Set是一种无序且唯一的集合(可以当成一个数学集合),它可以存储任何类型的值,包括对象、函数和原始类型等。它的结构类似数组,但是其中的值不允许重复,这点与Map的键值类似。

特点

  1. 成员的值都是唯一的
  2. 值的无序性(数据存储不依赖索引,而是哈希表)

属性及方法

创建及初始化

const set = new Set<string>()
console.log(set);// Set(0) {}

初始化可以使用[ value ]或任意数组进行赋值

const set = new Set<string>(['阿黄'])
console.log(set);// Set(1) { '阿黄' }

新增

Set的新增子项与Map不太一样,可以使用add函数进行操作

const set = new Set(['阿黄'])
set.add('小黑')
console.log(set);// Set(2) { '阿黄', '小黑' }

删除

set使用delete对集合的单项进行删除

const set = new Set<string>(['阿黄'])
set.delete('阿黄')
console.log(set);// Set(0) {}

其他属性

剩下的属性与Map几乎相同,用法上就不做赘述。此外,Set的迭代器方法比较特殊,使用set.values()和set.keys()的结果相同,因为Set的key和value都是value值

const set = new Set<string>(['阿黄'])
console.log(set.values()); // [Set Iterator] { '阿黄' }
console.log(set.keys()); // [Set Iterator] { '阿黄' }
console.log(set.entries()); // [Set Entries] { ['阿黄', '阿黄'] }

使用场景

数组去重

const set = new Set([6, 6, 4, 2, 3, 4, 3, 3, 1, 5, 5, 2]);
console.log(set);// Set(6) { 6, 4, 2, 3, 1, 5 }

集合操作

交集,并集,差集

const set = new Set([1, 2, 3, 4, 5]);
const set2 = new Set([1, 3, 5, 7, 9]);
// 交集
console.log([...set].filter(it => set2.has(it)));
// 并集
console.log(new Set([...set, ...set2]));
// 差集
console.log([...set].filter(it => !set2.has(it)));

WeakMap

在了解WeakMap之前,先看段代码

let obj: any = {
    name: "阿黄"
}
const map = new Map([[obj, "阿黄"]]);
obj = null
console.log(map);// Map(1) { { name: '阿黄' } => '阿黄' }

上面的代码中我们新建了一个object类型的变量,使其作为键赋值到Map中,当我们把obj删除时,Map中的键值没有发生变化,说明其二者是深复制关系,此时的obj存在与Map中不会被垃圾回收机制处理。此时如果我们想清除这个obj在Map中的引用对象,就可以使用WeakMap。

回到正题,WeakMap是一种弱引用的哈希表对象,就像上面的例子,如果键对象不再被引用,它将被垃圾回收并从WeakMap中自动删除,从而避免了内存泄漏的问题

特点

  1. 键名只能是对象
  2. 键名使用弱引用

属性及方法

创建及初始化

这与Map相似,只不过键名只能传对象类型的

let obj: any = {
    name: "阿黄"
}
const weakMap = new WeakMap([[obj, "阿黄"]]);

其他属性

WeakMap只拥有Map的get、set、has、delete这几个方法,不包含iterator迭代属性,也就是说clear需要手动一个一个删除

const obj = {
    name: "阿黄"
}
const obj2 = {
    name: "小黑"
}
const weakMap = new WeakMap([[obj, "阿黄"]]);
weakMap.set(obj2, "小黑")
weakMap.delete(obj)
console.log(weakMap.has(obj)); // false
console.log(weakMap.get(obj2)); // 小黑

使用场景

属性私有化

使用WeakMap可以对类的属性进行封装

const animalPrivate = new WeakMap()
class Animal {
    constructor() {
        animalPrivate.set(this, {
            name: "阿黄"
        })
    }
    getName() {
        return animalPrivate.get(this).name
    }
}
 
console.log(new Animal().getName());

避免内存泄漏

与Map效果不同,关联的object删除后weakMap键名也会删除

let obj: any = {
    name: "阿黄"
}
const weakMap = new WeakMap([[obj, "阿黄"]]);
console.log(weakMap.get(obj)); // 阿黄
obj = null
console.log(weakMap.get(obj)); // undefined

WeakSet

WeakSet和WeakMap一样,也可以避免内存泄漏,它的每一项只能传对象类型

特点

  1. 值只能是对象
  2. 值使用弱引用

属性及方法

创建及初始化

const obj = {
    name: "阿黄"
}
const weakSet = new WeakSet([obj]);

其他属性

WeakSet也是Set的简化版,只有add,delete,has三个属性,和WeakMap一样不支持iterator属性,无法迭代

const obj = {
    name: "阿黄"
}
const obj2 = {
    name: "小黑"
}
const weakSet = new WeakSet([obj]);
weakSet.add(obj2)
weakSet.delete(obj)
console.log(weakSet.has(obj));// false

使用场景

避免内存泄漏

这点和WeakMap一样

let obj: any = {
    name: "阿黄"
}
const weakSet = new WeakSet([obj]);
obj = null
console.log(weakSet.has(obj));// false

总结

本文主要介绍了ES6引入的四种新的数据结构,分别是Map(映射)、Set(集合)、WeakMap(弱映射)和WeakSet(弱集合)。Map键可以是任意类型,唯一且有序;Set键值合一并可以是任意值,唯一且无序;WeakMap是键限制为对象的青春版Map;WeakSet是值为对象的迷你版Set,Weak的二者的键被垃圾回收后即刻消失。

以上就是文章全部内容,如果文章有帮到你或觉得文章不错的,还请支持一下作者,谢谢!

相关文章
|
2月前
|
资源调度 JavaScript 前端开发
Day.js常用方法集合
Day.js常用方法集合
103 0
|
2月前
|
JavaScript 前端开发 定位技术
JavaScript 中如何代理 Set(集合) 和 Map(映射)
JavaScript 中如何代理 Set(集合) 和 Map(映射)
72 0
|
2月前
|
机器学习/深度学习 前端开发 JavaScript
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
81 0
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
|
14天前
|
存储 JavaScript 前端开发
JavaScript进阶-Map与Set集合
【6月更文挑战第20天】JavaScript的ES6引入了`Map`和`Set`,它们是高效处理集合数据的工具。`Map`允许任何类型的键,提供唯一键值对;`Set`存储唯一值。使用`Map`时,注意键可以非字符串,用`has`检查键存在。`Set`常用于数组去重,如`[...new Set(array)]`。了解它们的高级应用,如结构转换和高效查询,能提升代码质量。别忘了`WeakMap`用于弱引用键,防止内存泄漏。实践使用以加深理解。
|
2月前
|
JavaScript
js Array map映射对象多个属性
js Array map映射对象多个属性
18 0
|
11月前
|
前端开发
前端学习笔记202306学习笔记第三十六天-js-对象是属性的无序集合1
前端学习笔记202306学习笔记第三十六天-js-对象是属性的无序集合1
39 0
|
2月前
|
缓存 JavaScript 前端开发
从0开始学习JavaScript--JavaScript中的集合类
JavaScript中的集合类是处理数据的关键,涵盖了数组、Set、Map等多种数据结构。本文将深入研究这些集合类的创建、操作,以及实际应用场景,并通过丰富的示例代码,帮助大家更全面地了解和应用这些概念。
|
7月前
|
存储 JavaScript 前端开发
|
8月前
|
JavaScript
vue.js代码开发最常见的功能集合
vue.js代码开发最常见的功能集合
52 0