ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解


Posted in Javascript onFebruary 28, 2019

本文实例讲述了ES6中Set和Map数据结构,Map与其它数据结构互相转换操作。分享给大家供大家参考,具体如下:

ES6 的 Set:

ES6 提供了新的数据结构──Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set 本身是一个构造函数,用来生成 Set 数据结构。

Array和Set对比

都是一个存储多值的容器,两者可以互相转换,但是在使用场景上有区别。如下:

①Array的indexOf方法比Set的has方法效率低下
②Set不含有重复值(可以利用这个特性实现对一个数组的去重)
③Set通过delete方法删除某个值,而Array只能通过splice。两者的使用方便程度前者更优
④Array的很多新方法map、filter、some、every等是Set没有的(但是通过两者可以互相转换来使用)

一、Set 实例的操作方法:

let set = new Set();
set.add(1);
set.add("1");
console.log(set.size); // 2

可以使用数组来初始化一个 Set ,并且 Set 构造器会确保不重复地使用这些值:

let set = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
console.log(set.size); // 5

add(value): 添加某个值,返回Set结构本身
has(value): 返回布尔值,表示该值是否为Set的成员

let set = new Set();
set.add(1);
set.add("1");
console.log(set.has(1)); // true
console.log(set.has(6)); // false

delete(value): 删除某个值,返回一个布尔值,表示是否成功
clear(value):清除所有成员,没有返回值

let set = new Set();
set.add(1);
set.add("1");
console.log(set.has(1)); // true
set.delete(1);
console.log(set.has(5)); // false
console.log(set.size); // 1
set.clear();
console.log(set.size); // 0

二、Set遍历操作

keys():返回键名的遍历器
values(): 返回健值对的遍历器
entries():返回键值对的遍历器
forEach(): 每个成员

let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
 console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
 console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
 console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

forEach()

let set = new Set([1, 2]);
set.forEach(function(value, key, ownerSet) {
  console.log(key + ": " + value);
});
// 输出
// 1 :1
// 2: 2

三、ES6数组去重(面试也经常会问到数组去重的问题)

let arr = [1, 2, 2, 3];
let set = new Set(arr);
let newArr = Array.from(set);
console.log(newArr); // [1, 2, 3]

Set集合转化Array数组

let set = new Set([1, 2, 3, 3, 4]);
let arr = Array.from(set) //输出[1,2,3,4]

四、WeakSet

WeakSet结构与Set类似,它与Set有两个区别:

①weakSet的成员只能是对象,不能是其他类型的值;
②weakSet对象都是弱引用。如果其它对象不再引用该对象,那么垃圾回收机制会自动回收该对象所占的内存,所以WeakSet是不可遍历的。

WeakSet 结构有以下三个方法:

WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

WeakSet的一个用处是储存DOM节点,而不用担心这些节点会从文档中移除时,会引发内存泄露。

ES6的Map:

一、ES6 的 Map含义和基本用法

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。

const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false

上面代码使用 Map 结构的set方法,将对象o当作m的一个键,然后又使用get方法读取这个键,接着使用delete方法删除了这个键。

实例的属性和操作方法 § ⇧

二、Map 结构的实例有以下属性和操作方法:

1.size 属性

size属性返回 Map 结构的成员总数。

const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2

2.set(key, value)

set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

const m = new Map();
m.set('edition', 6)    // 键是字符串
m.set(262, 'standard')   // 键是数值
m.set(undefined, 'nah')  // 键是 undefined

set方法返回的是当前的Map对象,因此可以采用链式写法。

let map = new Map()
 .set(1, 'a')
 .set(2, 'b')
 .set(3, 'c');

3.get(key)

get方法读取key对应的键值,如果找不到key,返回undefined。

const m = new Map();
const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数
m.get(hello) // Hello ES6!

4.has(key)

has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

const m = new Map();
m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');
m.has('edition')   // true
m.has('years')    // false
m.has(262)      // true
m.has(undefined)   // true

5.delete(key)

delete方法删除某个键,返回true。如果删除失败,返回false。

const m = new Map();
m.set(undefined, 'nah');
m.has(undefined)   // true
m.delete(undefined)
m.has(undefined)    // false

6.clear()

clear方法清除所有成员,没有返回值。

let map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
map.clear()
map.size // 0

三、Map遍历方法

Map 结构原生提供三个遍历器生成函数和一个遍历方法:

keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历 Map 的所有成员。

需要特别注意的是,Map 的遍历顺序就是插入顺序。

const map = new Map([
 ['F', 'no'],
 ['T', 'yes'],
]);
for (let key of map.keys()) {
 console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
 console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
 console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
 console.log(key, value);
}
// "F" "no"
// "T" "yes"
// 等同于使用map.entries()
for (let [key, value] of map) {
 console.log(key, value);
}
// "F" "no"
// "T" "yes"

四、WeakMap

WeakMap结构与Map结构类似,也是用于生成键值对的集合。

// WeakMap 可以使用 set 方法添加成员
const wm1 = new WeakMap();
const key = {foo: 1};
wm1.set(key, 2);
wm1.get(key) // 2
// WeakMap 也可以接受一个数组,
// 作为构造函数的参数
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);
wm2.get(k2) // "bar"

WeakMap与Map的区别有两点:

首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。

const map = new WeakMap();
map.set(1, 2)
// TypeError: 1 is not an object!
map.set(Symbol(), 2)
// TypeError: Invalid value used as weak map key
map.set(null, 2)
// TypeError: Invalid value used as weak map key

上面代码中,如果将数值1和Symbol值作为 WeakMap 的键名,都会报错。其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。

WeakMap的设计目的在于,有时我们想在某个对象上面存放一些数据,但是这会形成对于这个对象的引用。请看下面的例子。

const e1 = document.getElementById('foo');
const e2 = document.getElementById('bar');
const arr = [
 [e1, 'foo 元素'],
 [e2, 'bar 元素'],
];

上面代码中,e1和e2是两个对象,我们通过arr数组对这两个对象添加一些文字说明。这就形成了arr对e1和e2的引用。一旦不再需要这两个对象,我们就必须手动删除这个引用,否则垃圾回收机制就不会释放e1和e2占用的内存。

// 不需要 e1 和 e2 的时候
// 必须手动删除引用
arr [0] = null;
arr [1] = null;

五、Map与其它数据结构的互相转换

1.Map 转为数组:

Map 转为数组最方便的方法,就是使用扩展运算符(...)。

const myMap = new Map()
 .set(true, 7)
 .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

2.数组 转为 Map:

将数组传入 Map 构造函数,就可以转为 Map。

new Map([
 [true, 7],
 [{foo: 3}, ['abc']]
])
// Map {
//  true => 7,
//  Object {foo: 3} => ['abc']
// }

3.Map 转为对象:

如果所有 Map 的键都是字符串,它可以转为对象。

function strMapToObj(strMap) {
 let obj = Object.create(null);
 for (let [k,v] of strMap) {
  obj[k] = v;
 }
 return obj;
}
const myMap = new Map()
 .set('yes', true)
 .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }

4.对象转为 Map:

function objToStrMap(obj) {
 let strMap = new Map();
 for (let k of Object.keys(obj)) {
  strMap.set(k, obj[k]);
 }
 return strMap;
}
objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}

5.Map 转为 JSON:

Map 转为 JSON 要区分两种情况。一种情况是,Map 的键名都是字符串,这时可以选择转为对象 JSON。

function strMapToJson(strMap) {
 return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'

另一种情况是,Map 的键名有非字符串,这时可以选择转为数组 JSON。

function mapToArrayJson(map) {
 return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'

6.JSON 转为 Map:

JSON 转为 Map,正常情况下,所有键名都是字符串。

function jsonToStrMap(jsonStr) {
 return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}

但是,有一种特殊情况,整个 JSON 就是一个数组,且每个数组成员本身,又是一个有两个成员的数组。这时,它可以一一对应地转为 Map。这往往是数组转为 JSON 的逆操作。

function jsonToMap(jsonStr) {
 return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
一个js封装的不错的选项卡效果代码
Feb 15 Javascript
javascript 有用的脚本函数
May 07 Javascript
javascript实现的基于金山词霸网络翻译的代码
Jan 15 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
May 16 Javascript
Mac系统下Webstorm快捷键整理大全
May 28 Javascript
js基于FileSaver.js 浏览器导出Excel文件的示例
Aug 15 Javascript
jQuery 开发之EasyUI 添加数据的实例
Sep 26 jQuery
基于vue2.x的电商图片放大镜插件的使用
Jan 22 Javascript
Vue页面骨架屏注入方法
May 13 Javascript
从0到1构建vueSSR项目之路由的构建
Mar 07 Javascript
JQuery的加载和选择器用法简单示例
May 13 jQuery
微信小程序与公众号卡券/会员打通的问题
Jul 25 Javascript
Vue CLI3.0中使用jQuery和Bootstrap的方法
Feb 28 #jQuery
Vue多组件仓库开发与发布详解
Feb 28 #Javascript
JavaScript数组去重的方法总结【12种方法,号称史上最全】
Feb 28 #Javascript
vue-cli3+typescript初体验小结
Feb 28 #Javascript
详解超简单的react服务器渲染(ssr)入坑指南
Feb 28 #Javascript
JS浅拷贝和深拷贝原理与实现方法分析
Feb 28 #Javascript
微信小程序搜索功能(附:小程序前端+PHP后端)
Feb 28 #Javascript
You might like
如何使用Gitblog和Markdown建自己的博客
2015/07/31 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
2015/11/17 PHP
对YUI扩展的Gird组件 Part-2
2007/03/10 Javascript
jQuery基础框架浅入剖析
2012/12/27 Javascript
js中substring和substr的详细介绍与用法
2013/08/29 Javascript
获取select元素被选中的文本内容的js代码
2014/01/29 Javascript
js简单实现交换Li的值
2014/05/22 Javascript
AngularJS中取消对HTML片段转义的方法例子
2015/01/04 Javascript
常用原生js自定义函数总结
2016/11/20 Javascript
AngularJS使用$http配置对象方式与服务端交互方法
2018/08/13 Javascript
微信小程序文章详情页面实现代码
2018/09/10 Javascript
微信小程序动态增加按钮组件
2018/09/14 Javascript
详解在vue-test-utils中mock全局对象
2018/11/07 Javascript
JavaScript动态检测密码强度原理及实现方法详解
2019/06/11 Javascript
JS将指定的某个字符全部转换为其他字符实例代码
2020/10/13 Javascript
Python使用bs4获取58同城城市分类的方法
2015/07/08 Python
如何在Django配置文件里配置session链接
2019/08/06 Python
Python学习笔记之While循环用法分析
2019/08/14 Python
通过python调用adb命令对App进行性能测试方式
2020/04/23 Python
浅谈tensorflow模型保存为pb的各种姿势
2020/05/25 Python
Python如何解除一个装饰器
2020/08/07 Python
Python如何获取文件路径/目录
2020/09/22 Python
Strawberrynet草莓网新加坡站:护肤、彩妆、香水及美发产品
2018/08/31 全球购物
什么是makefile? 如何编写makefile?
2012/08/08 面试题
Why do we need Unit test
2013/01/03 面试题
夜大毕业生自我评价分享
2013/11/10 职场文书
初中生期末考试的自我评价
2013/12/17 职场文书
新郎父亲婚宴答谢词
2014/01/11 职场文书
党员违纪检讨书
2014/02/18 职场文书
父母对孩子说的话
2014/04/12 职场文书
公司员工活动策划方案
2014/08/20 职场文书
学生会竞选演讲稿学习部
2014/08/25 职场文书
幸福中国演讲稿
2014/09/12 职场文书
擅自离岗检讨书
2014/09/12 职场文书
机票销售员态度不好检讨书
2014/09/27 职场文书
golang 实用库gotable的具体使用
2021/07/01 Golang