es6学习笔记-set和map数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成 Set 数据结构。
- const s = new Set();
- [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
- for (let i of s) {
- console.log(i);
- }
- // 2 3 5 4
上面代码通过add
方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。
Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
- // 例一
- const set = new Set([1, 2, 3, 4, 4]);
- [...set]
- // [1, 2, 3, 4]
- // 例二
- const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
- items.size //
- // 例三
- function divs () {
- return [...document.querySelectorAll('div')];
- }
- const set = new Set(divs());
- set.size //
- // 类似于
- divs().forEach(div => set.add(div));
- set.size //
展示了一种数组去重成员的方法
- // 去除数组的重复成员
- [...new Set(array)]
向 Set 加入值的时候,不会发生类型转换,所以5
和"5"
是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value equality”,它类似于精确相等运算符(===
),主要的区别是NaN
等于自身,而精确相等运算符认为NaN
不等于自身。
- let set = new Set();
- let a = NaN;
- let b = NaN;
- set.add(a);
- set.add(b);
- set // Set {NaN}
上面代码向 Set 实例添加了两个NaN
,但是只能加入一个。这表明,在 Set 内部,两个NaN
是相等。
另外,两个对象总是不相等的。
- let set = new Set();
- set.add({});
- set.size //
- set.add({});
- set.size //
上面代码表示,由于两个空对象不相等,所以它们被视为两个值。
Set实例的属性和方法
Set.prototype.constructor
:构造函数,默认就是Set
函数。Set.prototype.size
:返回Set
实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
add(value)
:添加某个值,返回 Set 结构本身。delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。has(value)
:返回一个布尔值,表示该值是否为Set
的成员。clear()
:清除所有成员,没有返回值。
- s.add(1).add(2).add(2);
- // 注意2被加入了两次
- s.size //
- s.has(1) // true
- s.has(2) // true
- s.has(3) // false
- s.delete(2);
- s.has(2) // false
Array.from
方法可以将 Set 结构转为数组。
- const items = new Set([1, 2, 3, 4, 5]);
- const array = Array.from(items);
这就提供了去除数组重复成员的另一种方法。
- function dedupe(array) {
- return Array.from(new Set(array));
- }
- dedupe([1, 1, 2, 3]) // [1, 2, 3]
遍历操作
Set 结构的实例有四个遍历方法,可以用于遍历成员。
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每个成员
需要特别指出的是,Set
的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
keys
方法、values
方法、entries
方法返回的都是遍历器对象(详见《Iterator 对象》一章)。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys
方法和values
方法的行为完全一致。
- 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"]
Set 结构的实例与数组一样,也拥有forEach
方法,用于对每个成员执行某种操作,没有返回值。
- set = new Set([1, 4, 9]);
- set.forEach((value, key) => console.log(key + ' : ' + value))
- // 1 : 1
- // 4 : 4
- // 9 : 9
上面代码说明,forEach
方法的参数就是一个处理函数。该函数的参数与数组的forEach
一致,依次为键值、键名、集合本身(上例省略了该参数)。这里需要注意,Set 结构的键名就是键值(两者是同一个值),因此第一个参数与第二个参数的值永远都是一样的。
扩展运算符(...
)内部使用for...of
循环,所以也可以用于 Set 结构。
- let set = new Set(['red', 'green', 'blue']);
- let arr = [...set];
- // ['red', 'green', 'blue']
扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。
- let arr = [3, 5, 2, 2, 5, 5];
- let unique = [...new Set(arr)];
- // [3, 5, 2]
WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象,而不能是其他类型的值。其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
WeakSet 是一个构造函数,可以使用new
命令,创建 WeakSet 数据结构。
- const ws = new WeakSet();
- const a = [[1, 2], [3, 4]];
- const ws = new WeakSet(a);
- // WeakSet {[1, 2], [3, 4]}
上面代码中,a
是一个数组,它有两个成员,也都是数组。将a
作为 WeakSet 构造函数的参数,a
的成员会自动成为 WeakSet 的成员。
- const b = [3, 4];
- const ws = new WeakSet(b);
- // Uncaught TypeError: Invalid value used in weak set(…)
上面代码中,数组b
的成员不是对象,加入 WeaKSet 就会报错
WeakSet 结构有以下三个方法。
- WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
- WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
- WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在
Map
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
- const data = {};
- const element = document.getElementById('myDiv');
- data[element] = 'metadata';
- data['[object HTMLDivElement]'] // "metadata"
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
- 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 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
- const map = new Map([
- ['name', '张三'],
- ['title', 'Author']
- ]);
- map.size //
- map.has('name') // true
- map.get('name') // "张三"
- map.has('title') // true
- map.get('title') // "Author"
上面代码在新建 Map 实例时,就指定了两个键name
和title
。
Map
构造函数接受数组作为参数,实际上执行的是下面的算法。
- const items = [
- ['name', '张三'],
- ['title', 'Author']
- ];
- const map = new Map();
- items.forEach(
- ([key, value]) => map.set(key, value)
- );
Set
和Map
都可以用来生成新的 Map。
- const set = new Set([
- ['foo', 1],
- ['bar', 2]
- ]);
- const m1 = new Map(set);
- m1.get('foo') //
- const m2 = new Map([['baz', 3]]);
- const m3 = new Map(m2);
- m3.get('baz') //
如果对同一个键多次赋值,后面的值将覆盖前面的值。
- const map = new Map();
- map
- .set(1, 'aaa')
- .set(1, 'bbb');
- map.get(1) // "bbb"
Map 结构的实例有以下属性和操作方法。
size属性
size
属性返回 Map 结构的成员总数。
set(key,value)
set
方法设置键名key
对应的键值为value
,然后返回整个 Map 结构。如果key
已经有值,则键值会被更新,否则就新生成该键。
set
方法返回的是当前的Map
对象,因此可以采用链式写法。
get(key)
get
方法读取key
对应的键值,如果找不到key
,返回undefined
。
has(key)
has
方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
delete(key)
delete
方法删除某个键,返回true
。如果删除失败,返回false
。
clear()
clear
方法清除所有成员,没有返回值。
Map 结构原生提供三个遍历器生成函数和一个遍历方法。
keys()
:返回键名的遍历器。values()
:返回键值的遍历器。entries()
:返回所有成员的遍历器。forEach()
:遍历 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"
Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...
)。
- const map = new Map([
- [1, 'one'],
- [2, 'two'],
- [3, 'three'],
- ]);
- [...map.keys()]
- // [1, 2, 3]
- [...map.values()]
- // ['one', 'two', 'three']
- [...map.entries()]
- // [[1,'one'], [2, 'two'], [3, 'three']]
- [...map]
- // [[1,'one'], [2, 'two'], [3, 'three']]
map数据结构与其他数据结构的相互转换
map转换成数组
Map 转为数组最方便的方法,就是使用扩展运算符(...
)。
- const myMap = new Map()
- .set(true, 7)
- .set({foo: 3}, ['abc']);
- [...myMap]
- // [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
数组转成map,将数组传入 Map 构造函数,就可以转为 Map。
- new Map([
- [true, 7],
- [{foo: 3}, ['abc']]
- ])
- // Map {
- // true => 7,
- // Object {foo: 3} => ['abc']
- // }
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 }
对象转成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}
map转成JSON
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}'
- 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"]]]'
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']}
WeakMap
WeakMap
结构与Map
结构类似,也是用于生成键值对的集合
首先,WeakMap
只接受对象作为键名(null
除外),不接受其他类型的值作为键名。其次,WeakMap
的键名所指向的对象,不计入垃圾回收机制。
es6学习笔记-set和map数据结构的更多相关文章
- JavaScript(ES6)学习笔记-Set和Map数据结构(一)
一.Set 1.ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. , , , , ']); s; // ...
- js-ES6学习笔记-Set和Map数据结构
1.ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. 2.Set 函数可以接受一个数组(或类似数组的对 ...
- es6 学习7 Set 和 Map 数据结构
Set 和 Map 数据结构 一.Set ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. const set = new Set([1, 2, 3, 4, ...
- ES6学习笔记(10)----Set和Map数据结构
参考书<ECMAScript 6入门>http://es6.ruanyifeng.com/ Set和Map数据结构 1.Set 基本用法 Set是一种新的数据结构,它的成员都是唯一 ...
- ES6中的Set与Map数据结构
本文实例讲述了ES6学习笔记之Set和Map数据结构.分享给大家供大家参考,具体如下: 一.Set ES6提供了新的数据结构Set.类似于数组,只不过其成员值都是唯一的,没有重复的值. Set本身是一 ...
- JS&ES6学习笔记(持续更新)
ES6学习笔记(2019.7.29) 目录 ES6学习笔记(2019.7.29) let和const let let 基本用法 let 不存在变量提升 暂时性死区 不允许重复声明 块级作用域 级作用域 ...
- ES6学习笔记之变量的解构赋值
变量的解构赋值 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 数组的解构赋值 以前,为变量赋值,只能直接指定值: 1 2 3 var a = 1; var b = 2; ...
- es6学习笔记-class之一概念
前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
随机推荐
- PHP基础入门(二)---入门基础知识必备
前言 在上一章中,我们初步了解了PHP的网页基础和PHP的入门基础,今天继续给大家分享更多有关PHP的知识. 理论知识看起来可能比较枯燥一些,但是我们的实践(敲代码)毕竟离不开它. 只有理论与实践相结 ...
- sftp无法连接问题
sftp连接linux 出现错误,就是服务器没有开sftp服务 解决:在linux服务器上,确保sftp定义在sshd的配置文件(一般为/etc/ssh/sshd_config)中:Subsystem ...
- js中的setTimeout和setinterval 用法说明
setTimeout("countSecond()", 1000)://countSecond()是函数(方法) setTimeout 只执行一次函数,需要传递两个参数1是函数名, ...
- week8
---恢复内容开始--- week8 1.动态导入模块 2.断言 3.ftp 4.socketserver 1.动态导入模块 import importlib a = importlib.import ...
- node遍历文件夹并读取文件内容
var fs = require('fs'); var path = require('path');//解析需要遍历的文件夹 var filePath = path.resolve('./dist' ...
- jdbc模板
public class JdbcTest { public static void main(String[] args) { //数据库连接 Connection connection = nul ...
- 关于if判断和switch
1.if判断: if(条件1){ 执行语句: } else if(条件2)}{ 执行语句2: } else{ 执行语句3: } if里面可以有无限个else if,而else if里面能嵌套无限个if ...
- react-native-router-flux
这是一个路由,可以用来做Android底部的导航栏,学Android的都知道,如果用原生的代码来 做导航栏,会很复杂,关系到很多复杂的知识. 接下来我就简单的说明一下如何插入和使用吧: 1.你要先依赖 ...
- javascript中的add(1)(2)(3)(4)是怎么实现的
javascript中的add(1)(2)(3)(4)是怎么实现的?实现如下: var fn = function(a){ let sum = a; let tempFn = function(b){ ...
- Python类之类的成员
对于一个学C++的朋友来说,Python类中,哪些是私有成员,哪些是共有成员,估计一直傻傻分不清. 一.本篇博客要解决的问题: Python类中,哪些是私有成员?哪些是共有成员? 二. 关于Pytho ...