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 相关文章推荐
父窗口获取弹出子窗口文本框的值
Jun 27 Javascript
IE event.srcElement和FF event.target 功能比较
Mar 01 Javascript
javascript使用eval或者new Function进行语法检查
Oct 16 Javascript
用JS控制回车事件的代码
Feb 20 Javascript
表单切换,用回车键替换Tab健(不支持IE)
Jul 20 Javascript
JS定时刷新页面及跳转页面的方法
Jul 04 Javascript
JS保留两位小数,多位小数的示例代码
Jan 07 Javascript
Javascript基础教程之数组 array
Jan 18 Javascript
Javascript中的高阶函数介绍
Mar 15 Javascript
JavaScript面向对象程序设计教程
Mar 29 Javascript
JavaScript实现url参数转成json形式
Sep 25 Javascript
VUE JS 使用组件实现双向绑定的示例代码
Jan 10 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
10个实用的PHP正则表达式汇总
2014/10/23 PHP
Thinkphp中volist标签mod控制一定记录的换行BUG解决方法
2014/11/04 PHP
PHP实现搜索时记住状态的方法示例
2018/05/11 PHP
jQuery $.each的用法说明
2010/03/22 Javascript
js对象的比较
2011/02/26 Javascript
千分位数字格式化(用逗号隔开 代码已做了修改 支持0-9位逗号隔开)的JS代码
2013/12/05 Javascript
js限制文本框只能输入数字方法小结
2014/06/16 Javascript
JavaScript高级教程5.6之基本包装类型(详细)
2015/11/23 Javascript
javascript中闭包(Closure)详解
2016/01/06 Javascript
jQuery实现的分子运动小球碰撞效果
2016/01/27 Javascript
完美的js图片轮换效果
2017/02/05 Javascript
详解vue-router基本使用
2017/04/18 Javascript
jQuery导航条固定定位效果实例代码
2017/05/26 jQuery
angular4 如何在全局设置路由跳转动画的方法
2017/08/30 Javascript
详细教你微信公众号正文页SVG交互开发技巧
2019/07/25 Javascript
python学习笔记:字典的使用示例详解
2014/06/13 Python
Python-OpenCV基本操作方法详解
2018/04/02 Python
TensorFlow实现随机训练和批量训练的方法
2018/04/28 Python
pandas DataFrame实现几列数据合并成为新的一列方法
2018/06/08 Python
python利用微信公众号实现报警功能
2018/06/10 Python
Python使用paramiko操作linux的方法讲解
2019/02/25 Python
详解python列表生成式和列表生成式器区别
2019/03/27 Python
将matplotlib绘图嵌入pyqt的方法示例
2020/01/08 Python
解决pyCharm中 module 调用失败的问题
2020/02/12 Python
python实现对变位词的判断方法
2020/04/05 Python
Django的ListView超详细用法(含分页paginate)
2020/05/21 Python
浅谈matplotlib中FigureCanvasXAgg的用法
2020/06/16 Python
css3 background属性调整增强介绍
2010/12/18 HTML / CSS
俄语地区最大的中国商品在线购物网站之一:Umka Mall
2019/11/03 全球购物
经济管理专业自荐信
2013/12/30 职场文书
4s店总经理岗位职责
2013/12/31 职场文书
护理专科自荐书范文
2014/02/18 职场文书
火锅店的活动方案
2014/08/15 职场文书
借名购房协议书范本
2014/10/06 职场文书
手把手教你实现PyTorch的MNIST数据集
2021/06/28 Python
golang实现浏览器导出excel文件功能
2022/03/25 Golang