详解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 多浏览器分别判断代码
Apr 01 Javascript
30个让人兴奋的视差滚动(Parallax Scrolling)效果网站
Mar 04 Javascript
基于mootools插件实现遮罩层新手引导
May 24 Javascript
JavaScript分秒倒计时器实现方法
Feb 02 Javascript
JavaScript中的this关键字使用详解
Aug 14 Javascript
javascript中return,return true,return false三者的用法及区别
Nov 17 Javascript
jquery移除了live()、die(),新版事件绑定on()、off()的方法
Oct 26 Javascript
JS键盘版计算器的制作方法
Dec 03 Javascript
利用原生js实现html5小游戏之打砖块(附源码)
Jan 03 Javascript
Vue 样式绑定的实现方法
Jan 15 Javascript
js实现鼠标切换图片(无定时器)
Jan 27 Javascript
vue使用localStorage持久性存储实现评论列表
Apr 14 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
php 404错误页面实现代码
2009/06/22 PHP
php图片处理:加水印、缩略图的实现(自定义函数:watermark、thumbnail)
2010/12/02 PHP
php引用返回与取消引用的详解
2013/06/08 PHP
php实现查询百度google收录情况(示例代码)
2013/08/02 PHP
php实现上传图片保存到数据库的方法
2015/02/11 PHP
CI框架实现cookie登陆的方法详解
2016/05/18 PHP
PHP操作MySQL中BLOB字段的方法示例【存储文本与图片】
2017/09/15 PHP
Laravel 集成微信用户登录和绑定的实现
2019/12/27 PHP
php设计模式之适配器模式实例分析【星际争霸游戏案例】
2020/04/07 PHP
基于PHP的登录和注册的功能的实现
2020/08/06 PHP
jquery ajax 检测用户注册时用户名是否存在
2009/11/03 Javascript
js iframe跨域访问(同主域/非同主域)分别深入介绍
2013/01/24 Javascript
javascript获取网页中指定节点的父节点、子节点的方法小结
2013/04/24 Javascript
基于JavaScript自定义构造函数的详解说明
2013/04/24 Javascript
教你用AngularJS框架一行JS代码实现控件验证效果
2014/06/23 Javascript
JavaScript实现身份证验证代码
2016/02/17 Javascript
js添加绑定事件的方法
2016/05/15 Javascript
javascript表单控件实例讲解
2016/09/13 Javascript
jQuery简单倒计时效果完整示例
2016/09/20 Javascript
Jil,高效的json序列化和反序列化库
2017/02/15 Javascript
react-native使用react-navigation进行页面跳转导航的示例
2017/09/07 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
vue-router实现编程式导航的代码实例
2019/01/19 Javascript
Element-UI+Vue模式使用总结
2020/01/02 Javascript
python多进程共享变量
2016/04/06 Python
巧用python和libnmapd,提取Nmap扫描结果
2016/08/23 Python
python实现嵌套列表平铺的两种方法
2018/11/08 Python
python pycharm最新版本激活码(永久有效)附python安装教程
2020/09/18 Python
Python3合并两个有序数组代码实例
2020/08/11 Python
HTML5表单验证特性(知识点小结)
2020/03/10 HTML / CSS
BAILEY 44官网:美国制造的女性服装
2019/07/01 全球购物
设计总监岗位职责
2013/12/07 职场文书
幼儿园英语教学反思
2014/01/30 职场文书
企业爱心捐款倡议书
2015/04/27 职场文书
django 认证类配置实现
2021/11/11 Python
SpringBoot全局异常处理方案分享
2022/05/25 Java/Android