详解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 相关文章推荐
javascript Ext JS 状态默认存储时间
Feb 15 Javascript
js实现点击注册按钮开始读秒倒计时的小例子
May 11 Javascript
jQuery使用fadein方法实现渐出效果实例
Mar 27 Javascript
js实现仿京东2级菜单效果(带延时功能)
Aug 27 Javascript
jQuery实现鼠标选文字发新浪微博的方法
Apr 02 Javascript
JavaScript实现无刷新上传预览图片功能
Aug 02 Javascript
AngularJS ionic手势事件的使用总结
Aug 09 Javascript
React如何将组件渲染到指定DOM节点详解
Sep 08 Javascript
浅谈react 同构之样式直出
Nov 07 Javascript
解决vuejs项目里css引用背景图片不能显示的问题
Sep 13 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
Jan 27 Javascript
微信小程序 button样式设置为图片的方法
Jun 19 Javascript
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+mysql写的留言本
2006/10/09 PHP
一个PHP分页类的代码
2011/05/18 PHP
php中创建和调用webservice接口示例
2014/07/25 PHP
微信开发之网页授权获取用户信息(二)
2016/01/08 PHP
php适配器模式简单应用示例
2019/10/23 PHP
5 cool javascript apps
2007/03/24 Javascript
Prototype Object对象 学习
2009/07/12 Javascript
js捕获鼠标滚轮事件代码
2013/12/16 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
js进行表单验证实例分析
2015/02/10 Javascript
Bootstrap响应式侧边栏改进版
2016/09/17 Javascript
jquery实现全选、全不选以及单选功能
2017/03/23 jQuery
详解基于 Nuxt 的 Vue.js 服务端渲染实践
2017/10/24 Javascript
开源一个微信小程序仪表盘组件过程解析
2019/07/30 Javascript
vue基于better-scroll仿京东分类列表
2020/06/30 Javascript
Python实现判断字符串中包含某个字符的判断函数示例
2018/01/08 Python
Appium Python自动化测试之环境搭建的步骤
2019/01/23 Python
如何通过Python实现标签云算法
2019/07/02 Python
详解Python Opencv和PIL读取图像文件的差别
2019/12/27 Python
python实现简单学生信息管理系统
2020/04/09 Python
Python并发concurrent.futures和asyncio实例
2020/05/04 Python
python 基于opencv去除图片阴影
2021/01/26 Python
HTML5如何为形状图上颜色怎么绘制具有颜色和透明度的矩形
2014/06/23 HTML / CSS
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
Lookfantastic澳大利亚官网:英国知名美妆购物网站
2021/01/07 全球购物
行政办公室岗位职责
2014/03/18 职场文书
家长学校工作方案
2014/05/07 职场文书
信用社主任竞聘演讲稿
2014/05/23 职场文书
公安学专业求职信
2014/07/27 职场文书
授权委托书
2014/09/17 职场文书
2016七夕情人节寄语
2015/12/04 职场文书
如何获取numpy array前N个最大值
2021/05/14 Python
只用Python就可以制作的简单词云
2021/06/07 Python
golang中的struct操作
2021/11/11 Golang
使用python绘制横竖条形图
2022/04/21 Python
postgresql中如何执行sql文件
2023/05/08 PostgreSQL