ES6 新特征之Map

ES6 给我们提供了 Map 数据结构,它类似于对象,用于保存键值对。不同的是,Map 中键的范围不限于字符串类型,各种类型的值(包括对象)都可以当作一个键或一个值。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果需要用到“键值对”的数据结构,MapObject 更合适。

Map和Object的区别

  • Object 中的键只能是字符串或者 Symbols 类型,但 Map 中的键可以是任意值。
  • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
  • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

创建Map

MapES6 提供给我们的构造函数,本质上是键值对的集合。任何值(对象或者原始值) 都可以作为一个键或一个值。

示例:

我们可以通过 Map() 方法来创建一个空 Map

let map = new Map();
console.log(map);  // 输出:Map {}

上述代码中,我们可以在创建时初始化 Map 时,Map 可以接收数组作为参数,并且数组成员也是一个个数组,其中包含两个元素,一个表示键,一个表示值。

示例:

例如下面这个 Map 中有两个键值对:

let map = new Map([["name","xkd"],['age','18']]);
console.log(map);
// 输出:Map { 'name' => 'xkd', 'age' => '18' }

第一个键值对中键为 name,值为 xkd,第二个键值对中键为 age,值为 18

Map的方法和属性

set()方法

set() 方法用于设置所对应的键值对,然后返回整个 Map 结构,如果已经有值,则键值会被更新,否则就会生成新的键。

示例:
let map = new Map();
map.set('name', 'xkd');
console.log(map);  // 输出:Map { 'name' => 'xkd' }

如果要设置多个键值对,则可以执行多次 set 方法。

示例:

例如向 map 中添加三个键值对:

let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
console.log(map);  
// 输出:Map { 'a' => 1, 'b' => 2, 'c' => 3 }

get()方法

get() 方法用于读取 key 对应的键值,如果找不到 key,则返回 undefined

示例:

下面代码中我们通过 set() 方法为 Map 设置键值对,然后通过 get() 方法获取指定键对应的值:

let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

console.log(map.get('a'));  // 输出:1
console.log(map.get('b'));  // 输出:2
console.log(map.get('c'));  // 输出:3
console.log(map.get('d'));  // 输出:undefined

可以看到,如果我们想要取读取的键值在 map 中不存在,例如 d,那么最终会输出 undefined

has()方法

has() 方法返回一个布尔值,表示某个键是否在 Map 数据结构中。在则返回 true,不在则返回 false

示例:
let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

console.log(map.has('a'));    // 输出:true
console.log(map.has('b'));    // 输出:true
console.log(map.has('name')); // 输出:false

上述代码中,我们先通过 set() 方法 向 map 中添加了三个键值对,但是很明显 ab 存在 map 数据结构中,而 name 不存在。

delete()方法

delete() 方法用于删除某个键,删除成功返回 true,如果删除失败则返回 false

示例:
let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

console.log(map.delete("a"));    // 输出:true
console.log(map.delete("age"));  // 输出:false

可以看到,因为 amap 中的键,所以删除 a 时返回 true 值。而 age 不是 map 中的键,所以返回 false

clear()方法

clear() 方法用于清除 Map 中所有成员,没有返回值。

示例:

Map 中的成员很多是,如果使用 delete() 方法一个键一个键删除会很麻烦,所以如果要清除 Map 中所有的成员,可以直接使用 clear() 方法:

let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

map.clear();
console.log(map);  // 输出:Map {}

size属性

size 属性可以用于返回 Map 中成员总数。

示例:
let map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);

console.log(map.size);  // 输出:3

Map 遍历方法

Map 原生提供三个遍历器生成函数和一个遍历方法。

示例:

我们先创建并初始化一个 Map

let map1 = new Map([
    ["x", 1],
    ["k", 2],
    ["d", 3]
]);

keys()方法

keys() 方法是一个用于返回键名的遍历器。

示例:

例如通过 keys() 方法遍历 map1

for(let key of map1.keys()){
    console.log(key);
}

输出:

x
k
d

从上述输出中可以看出,成功遍历了 map1 中的所有键值。

values()方法

values() 方法与 keys() 对应,是一个用于返回键值的遍历器。

示例:

例如通过 values() 方法遍历 map1

for(let v of map1.values()){
    console.log(v);
}

输出:

1
2
3

entries()方法

如果我们又想要遍历 Map 中的键又想要遍历 Map 中的值,可以使用 entries() 方法,entries() 方法用于返回所有成员的遍历器。

示例:
let map1 = new Map([
    ["x", 1],
    ["k", 2],
    ["d", 3]
]);
for(let [key,value] of map1.entries()){
    console.log(key+':'+value);
}

输出:

x:1
k:2
d:3

forEach()方法

forEach() 方法用于遍历 Map 的所有成员,第二个参数绑定 this

示例:
map1.forEach(function(value, key){
    console.log(key+':'+value);
});

输出:

x:1
k:2
d:3

Map的类型转换

Map 类型可以与其他的数据类型进行转换,我们一起来看一下。

示例:
  • Map 转为数组类型:可以使用扩展运算符... 来实现。
let map1 = new Map();
map1.set("name", "xkd");
console.log([...map1]);  
// 输出:[ [ 'name', 'xkd' ] ]
  • 数组类型转为 Map :将数组传入 Map 构造函数即可。
let map1 = new Map([
    ["x", 1],
    ["k", 2],
    ["d", 3]
]);
  • Map 转为对象:如果所有 Map 的键都是字符串,它可以无损地转为对象。如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名。
function strMapToObj(strMap) {
    let obj = Object.create(null);
    for (let [k,v] of strMap) {
      obj[k] = v;
    }
    return obj;
}
  
let map1 = new Map();
map1.set("name", "xkd");
console.log(strMapToObj(map1));  
// 输出:[Object: null prototype] { name: 'xkd' }
  • 对象转为 Map:可以使用 Object.entries() 方法来实现。
let obj = {"a":1, "b":2};
let map1 = new Map(Object.entries(obj));
console.log(map1); 
// 输出:Map { 'a' => 1, 'b' => 2 }
  • Map 转为 JSON:分为两种情况,一种是 Map 键名为字符串,这可以转为对象 JSON
function strMapToObj(strMap) {
    let obj = Object.create(null);
    for (let [k,v] of strMap) {
      obj[k] = v;
    }
    return obj;
}

function strMapToJson(strMap) {
    return JSON.stringify(strMapToObj(strMap));
}
  
let map1 = new Map().set('a', 1).set('b', 2);
console.log(strMapToJson(map1)); // 输出:{"a":1,"b":2}

还有一种情况是,Map 中的键名有非字符串,这时可以选择转为数组 JSON

function mapToArrayJson(map) {
    return JSON.stringify([...map]);
}
  
let map1 = new Map().set(true, 1).set({b: 2}, 2);
console.log(mapToArrayJson(map1));  // 输出:[[true,1],[{"b":2},2]]
  • JSON 转为 Map:如果所有键名都是字符串则可以像下面这个。
function objToStrMap(obj) {
    let strMap = new Map();
    for (let k of Object.keys(obj)) {
      strMap.set(k, obj[k]);
    }
    return strMap;
}
function jsonToStrMap(jsonStr) {
    return objToStrMap(JSON.parse(jsonStr));
}
  
console.log(jsonToStrMap('{"a": 1, "b": 2}'));  
// 输出:Map { 'a' => 1, 'b' => 2 }

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

function jsonToMap(jsonStr) {
    return new Map(JSON.parse(jsonStr));
}
  
console.log(jsonToMap('[[1, 100],[{"age":18},[20]]]'));
// 输出:Map { 1 => 100, { age: 18 } => [ 20 ] }

链接:https://www.9xkd.com/

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