详解ES6中的Map与Set集合


Posted in Javascript onMarch 22, 2019

集合的概念以及和数组的区别

其实数组也是集合, 只不过数组的索引是数值类型.当想用非数值类型作为索引时, 数组就无法满足需要了.

而 Map 集合可以保存多个键-值对(key-value),  Set 集合可以保存多个元素.

对Map 和 Set 一般不会逐一遍历其中的元素. Map 一般用来存储需要频繁取用的数据,  Set 一般用来判断某个值是否存在其中.

ES 5 中对 Map 和 Set 的模拟方法

在ES 5 中,没有 Set和Map集合, 一般使用对象来模拟这两种集合, 对象的属性作为键(key),  以属性值作为值(value),  即以 property: property-value 来模拟 key-value 的形式. 具体实现如下:

模拟 Map 的键值对集合:

// 创建一个 Map 对象
var map = Object.create(null);

// 添加属性和属性值, 即 添加 key 和 value
map.key1 = 'value 1';
map.key2 = {};

// 取得 key 对应的 value 
console.log(map.key1); // "value 1"
console.log(map.key2); // "Object {}"

模拟 Set :

// 创建一个 Set 对象
var set = Object.create(null);

// 添加属性和属性值, 即 添加 key 并令其值为 true, 即表示这个key存在于集合中
set.key = true;

// 判断 key 是否存在, 然后进行下一步的操作
if(set.key) { ... }

用对象模拟这两种集合的缺陷

由于对象中的属性名必须是字符串, 如果传入的不是字符串则会强制转换成对应的字符串类型

一般使用 if 语句来判断一个 key 是否存在于集合中,  当这个 key 对应的 value 为 false 或者可以被强制转换为 false 时,  则 if 语句认为这个key不存在.但是其实是存在的, 只不过 value = false 而已.

ES6 中的 Map 和 Set 集合

下面正式来讨论这两种集合的特点

Map

Map 中存储的是 key-value 形式的键值对,  其中的 key 和 value 可以是任何类型的,  即对象也可以作为 key . 这比用对象来模拟的方式就灵活了很多

Map 的创建和初始化

可以用new Map()构造函数来创建一个空的 Map

// 创建一个空的 Map 
let map = new Map();

也可以在 Map() 构造函数中传入一个数组来创建并初始化一个 Map. 传入的数组是二维数组, 其中的每一个子数组都有两个元素,  前者会被作为 key,  后者会被作为 value,  这样就形成了一个 key-value 键值对. 例如:

// 用数组来创建一个 非空的 Map 

let array = [ // 定义一个二维数组, 数组中的每子都有两个元素
  ['key1' , 'value 1'],  // key 是 字符串 "key1", value 是字符串 "value 1"
  [{} , 10086] ,     // key 是个对象, value 是数值 10086
  [ 5, {} ]       // key 是个数值类型, value 是对象
];

let map = new Map(array); // 将数组传入 Map 构造函数中

Map 可用的 方法

  1. set(key, value): 向其中加入一个键值对
  2. get(key): 若不存在 key 则返回 undefined
  3. has(key):返回布尔值
  4. delete(key): 删除成功则返回 true,  若key不存在或者删除失败会返回 false
  5. clear(): 将全部元素清除

size 属性, 属性值为 map 中键值对的个数

遍历方法 forEach()

和数组的 forEach 方法类似, 回调函数中都包含3个参数 值, 键, 和 调用这个方法的 Map 集合本身

map.forEach(function(value, key, ownerMap){
  console.log(key, value); // 每对键和值
  console.log(ownerMap === map); // true
});

Set 集合

Set 和 Map 最大的区别是只有键 key 而没有 value,  所以一般用来判断某个元素(key)是否存在于其中.

创建和初始化方法, 和 Map 大同小异

既可以创建一个空 set 也可以用数组来初始化一个非空的set. 和 Map 不同的是, 数组是一维数组, 每个元素都会成为 set 的键.例如:

// 创建一个数组
let array = [1, 'str'];   // 一维数组

// 用数组来初始化 set
let set = new Set(array);

set 的方法

1、add(key): 往set添加一个元素,  如果传入多个参数, 则只会把第一个加入进去

let set = new Set();
set.add(1, 2, 3);
console.log(set.has(1), set.has(2), set.has(3)); // true false false 可以看到只有第一个参数被加入进了 set

2、has(key)
3、delete(key)
4、clear()

遍历方法 forEach

和 Map 的 forEach 方法相似,  回调函数的参数也是3个 (value,  key,  ownerSet). 按道理来说因为 set 中只有 key 没有 value,  那么会掉函数中不应该存在 value 这个参数, 那么为什么这个 value 参数仍然存在呢?可能是因为 数组和 Map 的 forEach 方法的回调函数的参数都是这三个,  如果对于 Set 而改变了参数, 那么就会丢失了一致性. 这个理由......

那么既然没有 value , 那么这个value的值是什么呢?答案是和key 一样.我们可以把value和key 划等号了.下面这段代码可以验证这个说法.

set.forEach(function(value, key, ownerSet){
  console.log(value === key, set === ownerSet);  // true true
});

WeakSet 和 WeakMap

这两个集合比之前的两个集合在名字之前都加上了 Weak,  这个 Weak 可以直译成弱,  这个弱指的是弱引用,  那么前面不带Weak的 Set 和 Map就不弱, 就是强了,  这个强指的是强引用.

与 Set 和 Map 的区别

先说表层的区别:

  • 弱版本集合的 key 只能是对象,  对于 value 的类型没有限制.
  • 弱版本集合没有 forEach 方法, 也没有 for in 方法,  也不能用数组来初始化(会报错).
  • 弱版本可用的方法较少. WeakSet 只有 add, has, delete 方法可用; WeakMap 只有 set, has, get, delete 方法可用.

根本区别

弱版本的集合和它们对应的强版本根本的区别在对于对象的引用的强弱上,  而对象指的是 key 位置的对象, 即以对象为key的情况.

强弱版本对于 key 是对象时的引用机制如下:

将对象设置为 key 时, 就在集合中保存了这个对象的引用. 当这个对象没有其他引用了的时候, 即只有集合还引用着这个对象的时候, 弱类型的集合会放弃对这个对象的引用, 把这个对象从集合里移除, 不让它继续存在于集合中了, 有些“赶尽杀绝”的意思; 但是强类型的集合还会一直保存着对这个对象的引用, 就把它一直放在集合里.这就是 [WeakSet 和 WeakMap] 与 [Set 和 Map] 的根本区别.

要注意的是这个机制只作用于 key , 而 value 位置绑定的对象无论是否还存在别的引用, WeakMap 都不会放弃这个对象.只有这个位置的 key 绑定的对象没有其他引用时, 才会把 key 和 value 都放弃. 决定权在于 key 位置.

弱版本集合的主要用处

若版本集合可以用在需要生命周期管理的地方,例如保存对一个 DOM 对象的引用, 如果一个 DOM 对象使用完毕, 没有其他的引用了, 那么它应该被 垃圾回收,以免产生内存泄漏,那么弱版本的集合就最适合用来保存这样的对象了。

注意:四种集合都是有序的, 即元素被添加进去的顺序就是在内部保存的顺序. 对于用数组来初始化的集合也一样, 按照在数组中的位置依次添加进集合中.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JS中字符问题(二进制/十进制/十六进制及ASCII码之间的转换)
Nov 03 Javascript
js中如何把字符串转化为对象、数组示例代码
Jul 17 Javascript
Javascript中3种实现继承的方法和代码实例
Aug 12 Javascript
jQuery实现鼠标滑过Div层背景变颜色的方法
Feb 17 Javascript
JavaScript encodeURI 和encodeURIComponent
Dec 04 Javascript
JavaScript基于对象去除数组重复项的方法
Oct 09 Javascript
javascript另类方法实现htmlencode()与htmldecode()函数实例分析
Nov 17 Javascript
canvas时钟效果
Feb 16 Javascript
vue无限轮播插件代码实例
May 10 Javascript
layer扩展打开/关闭动画的方法
Sep 23 Javascript
three.js利用卷积法如何实现物体描边效果
Nov 27 Javascript
Vue CLI中模式与环境变量的深入详解
May 30 Vue.js
js控制随机数生成概率代码实例
Mar 21 #Javascript
详解bootstrap-fileinput文件上传控件的亲身实践
Mar 21 #Javascript
详解基于React.js和Node.js的SSR实现方案
Mar 21 #Javascript
javascript中call()、apply()的区别
Mar 21 #Javascript
vue实现微信获取用户信息的方法
Mar 21 #Javascript
vue里如何主动销毁keep-alive缓存的组件
Mar 21 #Javascript
基于node简单实现RSA加解密的方法步骤
Mar 21 #Javascript
You might like
上传文件先创建目录 再上传到目录里面去
2010/12/29 PHP
深入了解 register_globals (附register_globals=off 网站打不开的解决方法)
2012/06/27 PHP
php实现memcache缓存示例讲解
2013/12/04 PHP
PHP正则表达式 /i, /is, /s, /isU等介绍
2014/10/23 PHP
php从数据库中读取特定的行(实例)
2017/06/02 PHP
Jquery AutoComplete自动完成 的使用方法实例
2010/03/19 Javascript
javascript 折半查找字符在数组中的位置(有序列表)
2010/12/09 Javascript
关于jQuery object and DOM element
2013/04/15 Javascript
A标签触发onclick事件而不跳转的多种解决方法
2013/06/27 Javascript
利用js实现在浏览器状态栏显示访问者在本页停留的时间
2013/12/29 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
2014/01/28 Javascript
node.js中的fs.fstat方法使用说明
2014/12/15 Javascript
浅谈jquery中delegate()与live()
2015/06/22 Javascript
基于jQuery实现的美观星级评论打分组件代码
2015/10/30 Javascript
nuxt.js 缓存实践
2018/06/25 Javascript
微信小程序实现红包雨功能
2018/07/11 Javascript
微信小程序后台持续定位功能使用详解
2019/08/23 Javascript
NodeJS有难度的面试题(能答对几个)
2019/10/09 NodeJs
[04:00]DOTA2解说界神雕侠侣 CJ第四天谷子现场过生日
2013/07/30 DOTA
[52:27]2018DOTA2亚洲邀请赛 3.31 小组赛B组 paiN vs Secret
2018/04/01 DOTA
Python减少循环层次和缩进的技巧分析
2016/03/15 Python
详解python函数传参是传值还是传引用
2018/01/16 Python
tensorflow实现KNN识别MNIST
2018/03/12 Python
Python实现一个服务器监听多个客户端请求
2018/04/12 Python
Python使用re模块正则提取字符串中括号内的内容示例
2018/06/01 Python
Python assert关键字原理及实例解析
2019/12/13 Python
Django ORM实现按天获取数据去重求和例子
2020/05/18 Python
python request 模块详细介绍
2020/11/10 Python
CSS3使用多列制作瀑布流
2016/05/10 HTML / CSS
Merrell迈乐澳大利亚网站:购买户外登山鞋
2017/05/28 全球购物
联想瑞士官方网站:Lenovo Switzerland
2017/11/19 全球购物
马来西亚在线药房:RoyalePharma
2019/12/01 全球购物
创先争优活动承诺书
2014/08/30 职场文书
入党转正申请报告
2015/05/15 职场文书
Redis可视化客户端小结
2021/06/10 Redis
Python echarts实现数据可视化实例详解
2022/03/03 Python