es6学习笔记之Set和Map

一. Set

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

const s = new Set();
[2, 3, 4, 5, 4, 2].forEach( x => s.add(x));

for(let i of s){
    console.log(i);
}
// 2 3 4 5 

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

Set 函数可以接受一个数组,作为参数,用来初始化。

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  // 5

function div(){
    return [...document.querySelectorAll('div')];
}

const set = new Set(divs());
set.size // 56

es6数组去重:
[...new Set(array)]

向Set加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。类似于精确相等运算符(===)

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 // 1

set.add({});
set.size // 2
//上面代码表示,由于两个空对象不相等,所以它们被视为两个值。

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

Set 实例方法:
add(value):添加某个值,返回Set结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。

let s = new Set();

s.add(1).add(2).add(2);
//注意被加入两次
s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3)  // fasle

s.delete(2);
s.has(2) //false

Array.from 方法可以将Set结构转换为数组
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);

Tips: 这里出现数组去重的另一种方法

function unique(array){
    return Array.from(new Set(arrat));
}

unique([1, 1, 2, 3]); // [1, 2, 3]

Set 结构的实例有四个遍历方法,可以用于遍历成员。
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员

Tips: Set的遍历顺序就是插入顺序

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"]

可以省略values方法,直接用for...of循环遍历 Set。

let set = new Set(['red', 'green', 'blue']);
for(let x of set){
   console.log(x);
}

//red
//green
//blue

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

let set = new Set([1, 2, 3]);
set.forEach((value, key) => console(value*2))

//2
//4
//6

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

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

数组的map和filter方法也可以用于Set

let set = new Set([1, 2, 3]);
set = new Set([...set].map(x = x*2));
//返回Set结构: {2, 4, 6}

let set = new Set([1, 2, 3, 4, 5]);
set = new Set([...set].filter(x => (x % 2)== 0));
//返回Set结构{2, 4}

Set可以很容易地实现并集(Union)、交集(Intersect)和差集(Difference)。

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

//并集
let union = new Set([...a, ...b]);
//Set{1, 2, 3, 4}

//交集
let intersect = new Set([...a].filter(x => b.has(x)));
//Set {2, 3}

//差集
let differnce = new Set([...a].filter(x => !b.has(x)));
//Set {1}

二. Map

Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

const m  = new Map();
const o = { p : 'hello world'};

m.set(o, 'content');
m.get(o, 'content'); // 'content'

m.has(o);  //true
m.delete(o); //true
m.has(o); //false

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

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

const map = new  Map([
    ['name', 'mark'], ['title', 'Author']
]);

map.size //2
map.has('name'); // true;
map.get('name'); // 'mark'
map.has('title'); // true
map.get('title'); // 'Author'

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

const map = new   Map();
map.set(1, 'aaa')
       .set(1, 'bbb');

map.get(1); // "bbb"

Tips:上面代码对键1连续赋值两次,后一次的值覆盖前一次的值。

 //如果读取一个未知的键,则返回undefined。  
 new Map().get('asd');
 //undefined

只有对同一个对象的引用,Map 结构才将其视为同一个键。

const map = new Map();
map.set(['a'], 555);
map.get(['a']); // undefined

Tips:上面代码的set和get方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get方法无法读取该键,返回undefined。

const map = new Map();

const k1 = ['a'];
const k2 = ['a'];

map.set(k1, 111).set(k2, 222);
map.get(k1); //111
map.get(k2); //222

Tips:上面代码中,变量k1和k2的值是一样的,但是它们在 Map 结构中被视为两个键。

Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。

let map = new Map();
map.set(-0, 123);
map.get(+0); //123

map.set(true, 1);
map.set('true', 2);
map.get(true); //1

map.set(undefined, 3);
map.set(null, 4);
map.get(undefined); //3

map.set(NaN, 123);
map.get(NaN) //123

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, 'asd'); //键是undefinde

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, 'lalala'); // 键是函数
 m.get(hello); // 'lalala'

4.has(key)

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

const m = new Map();
m.set('edition', 6);
m.set(262, 'standard');
m.set(undefind, 'asd');

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(undfined, 'asd');
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

7.遍历方法

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 [key, value] of map.entries){
  console.log(key, value);
}

// "F" "no"
// "T" "yes"

//等同于
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.value()]
//['one' , 'two', 'three']

[...map.entries()]
//[['1', 'one'], ['2', 'two'], ['3', 'three']]

[...map]
//[['1', 'one'], ['2', 'two'], ['3', 'three']]

结合数组的map方法、filter方法,可以实现 Map 的遍历和过滤(Map 本身没有map和filter方法)。

 const map0 = new Map([
      [1, 'a'],
      [2, 'b'],
      [3, 'c']
  ]);

const map1 = new Map([...map0.filter(k, v) => k <3]);
  //产生 Map 结构 {1 => 'a', 2 => 'b'}

const map2 =  new Map(
  [...map0].map([k, v] => [k *2, '_' + v])
);
//产生Map结构{2 => '_a', 4 => '_b', 6 => '_c'}

Map 还有一个forEach方法,与数组的forEach方法类似,也可以实现遍历。

map.forEach(function(value, key, map){ console.log(key, value); });

三. 与其他结构的数据互换

1.Map 转为数组

const map = new Map()
          .set(ture, 7)
          .set('23', 23);
[...map]
//[[true, 7], ['23', 23]]

2.数组 转为 Map

  const map = new Map([
        [1, 'a'],
        [2, 'b'],
        [3, 'c']
    ]);

3.Map 转为对象

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

function strMapToObj(strMap){
    let obj = Object.create(null);
    for(let [k, v] of strMap){
      obj[k] = v
    }
  return obj;
}

const map = new  Map()
          .set('yes', true)
          .set('no', false);

strMapToObj(map);
//{yes : true, no : false}

4.对象转为Map

function objToStrMap(obj){
  let strMap = new Map();
  for(let k of Objcet.keys(obj)){
     strMap.set(k , obj[k]);
  }
  return strMap;
}

5.map 转为 json

//Map 的键名都是字符串
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('2', 2);
  mapToArrayJson(myMap);

6.Json转为Map

//JSON 转为 Map,正常情况下,所有键名都是字符串。
function jsonToStrMap(jsonStr){
    retrurn objTostrMap(JSON.parse(jsonstr));
}

jsonToStrMap('{"yes" : true, "no" : false}')

//Map {'yes' => true, 'no' => no}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容