ES6中的 Map Set 使用汇总

Map

ES6提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值,包括对象都可以当作键。
即,Object结构提供了 字符串-值 的对应,Map结构提供了 值-值 的对应,是一种更完善的Hash结构实现。
Map的数据形式是一个二维数组,一种红黑树的数据结构,键是唯一的。

Map语法

如何新建Map对象

# 初始化
let key1 = 12;
let value1 = 'test';
let m_1 = new Map();
let m_2 = new Map([[key1, value1]]);

其他的属性和方法如下表格所示

属性/方法 作用 例子
size 返回成员数量 m_1.size 结果为 0
clear() 清空所有成员,无返回值 m_1.clear()
has(key) 判断是否存在指定成员,返回值为 true / false m_1.has(key)
get(key) 获取指定成员的值,如不存在则返回 undefined m_1.get(key)
set(key, value) 为key设置键值,如已经存在该key则更新,否则添加新元素,返回值是实例本身 m_1.set(key, value)
delete(key) 删除key的键值对,返回值为 true / false m_1.delete(key)

如何遍历Map对象

# 使用 forEach
对象.forEach(function (value, key/index, 对象本省){
    // 对象的每个元素都将执行...
    // 针对Map对象,函数的变量就是元素的value、元素的key、整个对象
    // 针对Array对象,函数的变量就是元素的value、元素的索引(从0开始)、整个对象
});

# 使用 for
for (let [key, value] of m_1) {
    // key和value就是Map对象某个元素的key与value
}

Map使用上需要警惕的地方

Map对象的键为应用类型的时候,例如键为一个Array对象,在这样的场景下,Map只有对同一个对象的引用,才将其视为同一个键,也就是根据内存来寻址的,例如如下例子,set和get的键表面上是同一个值,但是实际上存放的内存不一样,所以get返回undefined

m_1.set([], 1);
m_1.get([]);  // 返回值为 undefined

那么如果我们想要获取到set指定的变量怎么办呢?也就是需要知道set指定的键存放的内存地址在哪里,显然我们需要对其进行存储,如下例子

let key_1 = [];
let key_2 = [];

m_1.set(key_1, 1)
   .set(key_2, 2);

m_1.get(key_1);  // 返回值为 1
m_1.get(key_2);  // 返回值为 2

Map与其他类型的数据的转换

Map 转为 Array

使用扩展运算符 ...,例如如下例子

let m_1 = new Map([[1, 'name'], ['name', 'js']]);
[...m_1];  // 返回值为 [[1,"name"],["name","js"]]

Array 转为 Map

将数组转入Map构造函数中,初始化的时候就可以进行转换,注意这里的数组需要是一个二位数组才可以,并且如果该数组中有元素的key相同的情况,后面的元素的value会覆盖前面的,例如

let arr = [[1, 12], [1, 24], ['name', 'ji'], ['name', 'js']];
let arr_to_m = new Map(arr);
arr_to_m  // 返回值为 Map(2) {1 => 24, "name" => "js"}

Map转为对象

上面说到了对象是key为string类型的键值对,所以如果Map所有元素的key为string类型时,是可以进行Map转化为对象的操作的,具体如下

function strmap_to_object (strmap) {
    let obj = {};
    for (let [key, value] of strmap) {
        obj[key] = value;
    }
    return obj;
}

let strmap = new Map([['name', 'js'], ['age', 18]]);
strmap_to_object(strmap);  // 返回值为 {name: "js", age: 18}

对象转为Map

和上面操作反着来,可以实现对象转化为Map的操作,具体如下

function object_to_strmap (obj) {
    let obj_keys = Object.keys(obj);
    let strmap = new Map();

    for (let item of obj_keys) {
        strmap.set(item, obj[item]);
    }
    return strmap;
}

let obj = {name: 'js', age: 18}
object_to_strmap(obj);  // 返回值为 Map(2) {"name" => "js", "age" => 18}

Map转为JSON

Map转为JSON,建议是将其转化为Array之后,再使用 JSON.stringify 函数来实现转换,这样可以保证Map中的键为任何类型的情况

JSON转化为Map

JSON转化为Map这要区分一下情况,如果该JSON串是一个Array的话,且满足二维数组,那么可以直接使用Map在定义的时候进行初始化;如果该JSON串是一个对象的话,需要先转化为对象,然后使用上述关于 对象转为Map 中提到的方法

Set

ES6提供了Set数据结构,它类似于数组,但是存储的元素都是唯一的,这里的唯一指的是他们存储的内存位置是唯一。

Set语法

如何新建Set对象

# 初始化
let ele = 12;
let s_1 = new Set();
let s_2 = new Set([ele]);

其他的属性和方法如下表格所示

属性/方法 作用 例子
size 返回成员数量 s_1.size 结果为 0
clear() 清空所有成员,无返回值 s_1.clear()
has(ele) 判断是否存在指定成员,返回值为 true / false s_1.has(ele)
add(ele) 添加元素ele,如果已经存在,没有变动,否则添加,返回值是实例本身 s_1.add(ele)
delete(ele) 删除某个值,返回值为 true / false s_1.delete(ele)

如何遍历Set对象

# 使用 forEach
对象.forEach(function (value, key/index, 对象本省){
    // 对象的每个元素都将执行...
    // 针对Set对象,函数的变量就是元素的value、元素的key、整个对象,其中Set对象的key和value相同而已
    // 针对Array对象,函数的变量就是元素的value、元素的索引(从0开始)、整个对象
});

# 使用 for
for (let ele of s_1) {
    // ele是Set对象的元素值
}

# 使用Set对象的遍历器
对象.keys()  // 返回对象的所有key组成的一个遍历器
对象.values()  // 返回对象的所有value组成的一个遍历器
对象.entries()  // 返回对象的所有[key, value]组成的一个遍历器

Set使用上需要警惕的地方

由于Set中元素的独一无二,根据内存地址来进行判断,所以如果有多个元素是引用型的话,尽管值相同,但是内存地址不同,那么在Set对象中也将会存储多份,和Map类似

Set的其他操作

实现Set的并集和交集

Set对象可以通过扩展运算符 ... 快速的实现转为Array,那么这样我就可以实现Set的并集了,例如

let s_1 = new Set([12, 34, 45]);
let s_2 = new Set([12, 33, 44]);

let union_set = new Set([...s_1, ...s_2]); // 实现并集 s_1 u s_2
let intersect_set = new Set([...a].filter(x => s_2.has(x)));  // 实现交集 s_1 n s_2

实现Set的更新

如果想在遍历的过程中,同步改变原来的Set结构,目前没有直接的方法,可以通过如下两种方法来实现,但是其实都是创建了一个新的Set,然后复制给原来的Set变量

# 利用原Set结构映射出一个新的结构
let s_1 = new Set([1]);
s_1 = new Set([...s_1].map(x => opt(x)));

# 利用 Array.from 方法
let s_1 = new Set([1]);
s_1 = new Set(Array.from(s_1, x => opt(x)));

其他

在讲述Map和Set的时候,都用到了扩展运算符 ...,这里着重说明一下该运算符,它的功能是将一个数组转为用逗号分隔的参数序列,主要用于函数调用,例如数组的合并,如下,但是有一个局限性,就是被合并数组 arr_2 元素个数不能太大,大致是 100, 000会有问题 参考

let arr_1 = [1, 2, 3];
let arr_2 = [1, 4, 5];
arr_1.push(...arr_2);  
arr_1 // 返回值为 [1, 2, 3, 1, 4, 5]

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

推荐阅读更多精彩内容