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

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

  1. const s = new Set();
  2.  
  3. [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
  4.  
  5. for (let i of s) {
  6. console.log(i);
  7. }
  8. // 2 3 5 4

上面代码通过add方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。

Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

  1. // 例一
  2. const set = new Set([1, 2, 3, 4, 4]);
  3. [...set]
  4. // [1, 2, 3, 4]
  5.  
  6. // 例二
  7. const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
  8. items.size //
  9.  
  10. // 例三
  11. function divs () {
  12. return [...document.querySelectorAll('div')];
  13. }
  14.  
  15. const set = new Set(divs());
  16. set.size //
  17.  
  18. // 类似于
  19. divs().forEach(div => set.add(div));
  20. set.size //

展示了一种数组去重成员的方法

  1. // 去除数组的重复成员
  2. [...new Set(array)]

向 Set 加入值的时候,不会发生类型转换,所以5"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value equality”,它类似于精确相等运算符(===),主要的区别是NaN等于自身,而精确相等运算符认为NaN不等于自身。

  1. let set = new Set();
  2. let a = NaN;
  3. let b = NaN;
  4. set.add(a);
  5. set.add(b);
  6. set // Set {NaN}

上面代码向 Set 实例添加了两个NaN,但是只能加入一个。这表明,在 Set 内部,两个NaN是相等。

另外,两个对象总是不相等的。

  1. let set = new Set();
  2.  
  3. set.add({});
  4. set.size //
  5.  
  6. set.add({});
  7. set.size //

上面代码表示,由于两个空对象不相等,所以它们被视为两个值。

Set实例的属性和方法

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

  • add(value):添加某个值,返回 Set 结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。
  1. s.add(1).add(2).add(2);
  2. // 注意2被加入了两次
  3.  
  4. s.size //
  5.  
  6. s.has(1) // true
  7. s.has(2) // true
  8. s.has(3) // false
  9.  
  10. s.delete(2);
  11. s.has(2) // false

Array.from方法可以将 Set 结构转为数组。

  1. const items = new Set([1, 2, 3, 4, 5]);
  2. const array = Array.from(items);

这就提供了去除数组重复成员的另一种方法。

  1. function dedupe(array) {
  2. return Array.from(new Set(array));
  3. }
  4.  
  5. dedupe([1, 1, 2, 3]) // [1, 2, 3]

遍历操作

Set 结构的实例有四个遍历方法,可以用于遍历成员。

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

需要特别指出的是,Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。

keys方法、values方法、entries方法返回的都是遍历器对象(详见《Iterator 对象》一章)。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

  1. let set = new Set(['red', 'green', 'blue']);
  2.  
  3. for (let item of set.keys()) {
  4. console.log(item);
  5. }
  6. // red
  7. // green
  8. // blue
  9.  
  10. for (let item of set.values()) {
  11. console.log(item);
  12. }
  13. // red
  14. // green
  15. // blue
  16.  
  17. for (let item of set.entries()) {
  18. console.log(item);
  19. }
  20. // ["red", "red"]
  21. // ["green", "green"]
  22. // ["blue", "blue"]

Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。

  1. set = new Set([1, 4, 9]);
  2. set.forEach((value, key) => console.log(key + ' : ' + value))
  3. // 1 : 1
  4. // 4 : 4
  5. // 9 : 9

上面代码说明,forEach方法的参数就是一个处理函数。该函数的参数与数组的forEach一致,依次为键值、键名、集合本身(上例省略了该参数)。这里需要注意,Set 结构的键名就是键值(两者是同一个值),因此第一个参数与第二个参数的值永远都是一样的。

扩展运算符(...)内部使用for...of循环,所以也可以用于 Set 结构。

  1. let set = new Set(['red', 'green', 'blue']);
  2. let arr = [...set];
  3. // ['red', 'green', 'blue']

扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。

  1. let arr = [3, 5, 2, 2, 5, 5];
  2. let unique = [...new Set(arr)];
  3. // [3, 5, 2]

WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。

首先,WeakSet 的成员只能是对象,而不能是其他类型的值。其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

WeakSet 是一个构造函数,可以使用new命令,创建 WeakSet 数据结构。

  1. const ws = new WeakSet();
  1. const a = [[1, 2], [3, 4]];
  2. const ws = new WeakSet(a);
  3. // WeakSet {[1, 2], [3, 4]}

上面代码中,a是一个数组,它有两个成员,也都是数组。将a作为 WeakSet 构造函数的参数,a的成员会自动成为 WeakSet 的成员。

  1. const b = [3, 4];
  2. const ws = new WeakSet(b);
  3. // 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 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

  1. const data = {};
  2. const element = document.getElementById('myDiv');
  3.  
  4. data[element] = 'metadata';
  5. data['[object HTMLDivElement]'] // "metadata"

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

  1. const m = new Map();
  2. const o = {p: 'Hello World'};
  3.  
  4. m.set(o, 'content')
  5. m.get(o) // "content"
  6.  
  7. m.has(o) // true
  8. m.delete(o) // true
  9. m.has(o) // false

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

作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

  1. const map = new Map([
  2. ['name', '张三'],
  3. ['title', 'Author']
  4. ]);
  5.  
  6. map.size //
  7. map.has('name') // true
  8. map.get('name') // "张三"
  9. map.has('title') // true
  10. map.get('title') // "Author"

上面代码在新建 Map 实例时,就指定了两个键nametitle

Map构造函数接受数组作为参数,实际上执行的是下面的算法。

  1. const items = [
  2. ['name', '张三'],
  3. ['title', 'Author']
  4. ];
  5.  
  6. const map = new Map();
  7.  
  8. items.forEach(
  9. ([key, value]) => map.set(key, value)
  10. );

SetMap都可以用来生成新的 Map。

  1. const set = new Set([
  2. ['foo', 1],
  3. ['bar', 2]
  4. ]);
  5. const m1 = new Map(set);
  6. m1.get('foo') //
  7.  
  8. const m2 = new Map([['baz', 3]]);
  9. const m3 = new Map(m2);
  10. m3.get('baz') //

如果对同一个键多次赋值,后面的值将覆盖前面的值。

  1. const map = new Map();
  2.  
  3. map
  4. .set(1, 'aaa')
  5. .set(1, 'bbb');
  6.  
  7. 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 的所有成员。
  1. const map = new Map([
  2. ['F', 'no'],
  3. ['T', 'yes'],
  4. ]);
  5.  
  6. for (let key of map.keys()) {
  7. console.log(key);
  8. }
  9. // "F"
  10. // "T"
  11.  
  12. for (let value of map.values()) {
  13. console.log(value);
  14. }
  15. // "no"
  16. // "yes"
  17.  
  18. for (let item of map.entries()) {
  19. console.log(item[0], item[1]);
  20. }
  21. // "F" "no"
  22. // "T" "yes"
  23.  
  24. // 或者
  25. for (let [key, value] of map.entries()) {
  26. console.log(key, value);
  27. }
  28. // "F" "no"
  29. // "T" "yes"
  30.  
  31. // 等同于使用map.entries()
  32. for (let [key, value] of map) {
  33. console.log(key, value);
  34. }
  35. // "F" "no"
  36. // "T" "yes"

Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)。

  1. const map = new Map([
  2. [1, 'one'],
  3. [2, 'two'],
  4. [3, 'three'],
  5. ]);
  6.  
  7. [...map.keys()]
  8. // [1, 2, 3]
  9.  
  10. [...map.values()]
  11. // ['one', 'two', 'three']
  12.  
  13. [...map.entries()]
  14. // [[1,'one'], [2, 'two'], [3, 'three']]
  15.  
  16. [...map]
  17. // [[1,'one'], [2, 'two'], [3, 'three']]

map数据结构与其他数据结构的相互转换

map转换成数组

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

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

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

  1. new Map([
  2. [true, 7],
  3. [{foo: 3}, ['abc']]
  4. ])
  5. // Map {
  6. // true => 7,
  7. // Object {foo: 3} => ['abc']
  8. // }

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

  1. function strMapToObj(strMap) {
  2. let obj = Object.create(null);
  3. for (let [k,v] of strMap) {
  4. obj[k] = v;
  5. }
  6. return obj;
  7. }
  8.  
  9. const myMap = new Map()
  10. .set('yes', true)
  11. .set('no', false);
  12. strMapToObj(myMap)
  13. // { yes: true, no: false }

对象转成map

  1. function objToStrMap(obj) {
  2. let strMap = new Map();
  3. for (let k of Object.keys(obj)) {
  4. strMap.set(k, obj[k]);
  5. }
  6. return strMap;
  7. }
  8.  
  9. objToStrMap({yes: true, no: false})
  10. // Map {"yes" => true, "no" => false}

map转成JSON

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

  1. function strMapToJson(strMap) {
  2. return JSON.stringify(strMapToObj(strMap));
  3. }
  4.  
  5. let myMap = new Map().set('yes', true).set('no', false);
  6. strMapToJson(myMap)
  7. // '{"yes":true,"no":false}'
  1. function mapToArrayJson(map) {
  2. return JSON.stringify([...map]);
  3. }
  4.  
  5. let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
  6. mapToArrayJson(myMap)
  7. // '[[true,7],[{"foo":3},["abc"]]]'

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

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

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

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

WeakMap

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

首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。

es6学习笔记-set和map数据结构的更多相关文章

  1. JavaScript(ES6)学习笔记-Set和Map数据结构(一)

    一.Set 1.ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. , , , , ']); s; // ...

  2. js-ES6学习笔记-Set和Map数据结构

    1.ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. 2.Set 函数可以接受一个数组(或类似数组的对 ...

  3. es6 学习7 Set 和 Map 数据结构

     Set 和 Map 数据结构 一.Set ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. const set = new Set([1, 2, 3, 4, ...

  4. ES6学习笔记(10)----Set和Map数据结构

    参考书<ECMAScript 6入门>http://es6.ruanyifeng.com/ Set和Map数据结构 1.Set  基本用法    Set是一种新的数据结构,它的成员都是唯一 ...

  5. ES6中的Set与Map数据结构

    本文实例讲述了ES6学习笔记之Set和Map数据结构.分享给大家供大家参考,具体如下: 一.Set ES6提供了新的数据结构Set.类似于数组,只不过其成员值都是唯一的,没有重复的值. Set本身是一 ...

  6. JS&ES6学习笔记(持续更新)

    ES6学习笔记(2019.7.29) 目录 ES6学习笔记(2019.7.29) let和const let let 基本用法 let 不存在变量提升 暂时性死区 不允许重复声明 块级作用域 级作用域 ...

  7. ES6学习笔记之变量的解构赋值

    变量的解构赋值 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 数组的解构赋值 以前,为变量赋值,只能直接指定值: 1 2 3 var a = 1; var b = 2; ...

  8. es6学习笔记-class之一概念

    前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...

  9. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

随机推荐

  1. PHP基础入门(二)---入门基础知识必备

    前言 在上一章中,我们初步了解了PHP的网页基础和PHP的入门基础,今天继续给大家分享更多有关PHP的知识. 理论知识看起来可能比较枯燥一些,但是我们的实践(敲代码)毕竟离不开它. 只有理论与实践相结 ...

  2. sftp无法连接问题

    sftp连接linux 出现错误,就是服务器没有开sftp服务 解决:在linux服务器上,确保sftp定义在sshd的配置文件(一般为/etc/ssh/sshd_config)中:Subsystem ...

  3. js中的setTimeout和setinterval 用法说明

    setTimeout("countSecond()", 1000)://countSecond()是函数(方法) setTimeout 只执行一次函数,需要传递两个参数1是函数名, ...

  4. week8

    ---恢复内容开始--- week8 1.动态导入模块 2.断言 3.ftp 4.socketserver 1.动态导入模块 import importlib a = importlib.import ...

  5. node遍历文件夹并读取文件内容

    var fs = require('fs'); var path = require('path');//解析需要遍历的文件夹 var filePath = path.resolve('./dist' ...

  6. jdbc模板

    public class JdbcTest { public static void main(String[] args) { //数据库连接 Connection connection = nul ...

  7. 关于if判断和switch

    1.if判断: if(条件1){ 执行语句: } else if(条件2)}{ 执行语句2: } else{ 执行语句3: } if里面可以有无限个else if,而else if里面能嵌套无限个if ...

  8. react-native-router-flux

    这是一个路由,可以用来做Android底部的导航栏,学Android的都知道,如果用原生的代码来 做导航栏,会很复杂,关系到很多复杂的知识. 接下来我就简单的说明一下如何插入和使用吧: 1.你要先依赖 ...

  9. javascript中的add(1)(2)(3)(4)是怎么实现的

    javascript中的add(1)(2)(3)(4)是怎么实现的?实现如下: var fn = function(a){ let sum = a; let tempFn = function(b){ ...

  10. Python类之类的成员

    对于一个学C++的朋友来说,Python类中,哪些是私有成员,哪些是共有成员,估计一直傻傻分不清. 一.本篇博客要解决的问题: Python类中,哪些是私有成员?哪些是共有成员? 二. 关于Pytho ...