最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

Map数据结构详解

来源:博客园

Map

Object本质上是键值对的集合(Hash结构),但Object只能将字符串当做键,这就给Object带来了很大的限制。


(资料图片)

let data = {}let s = {     name : "东方不败" }data[s] = "西方求败"// 如果键传入非字符串的值,会自动为字符串console.log(data);  // {[object Object]: "西方求败"}console.log(data["[object Object]"]);  // 西方求败

为了解决这个问题,es6提供了Map数据结构。它类似于对象,也是键值对集合,但键不局限于字符串,各种类型的值都可以当做键。

  • Object结构:字符串键:值
  • Map结构:值键:值
let data2 = new Map()let s2 = {     name : "艺术概论"}data2.set(s2,"中国工艺美术史")console.log(data2.get(s2));  // 中国工艺美术史console.log(data2);  // key: {name: "艺术概论"} , value : "中国工艺美术史"

上面案例使用Mapset方法,将s2当做data2的键,使用get方法取值。

Map的一些常用方法

方法说明
set()为Map对象添加一个指定键(key)和值(value)的新元素
get()用来获取Map对象中指定的元素
has()返回boolean值,用来表明Map中是否存在该元素
delete()删除对应元素
size返回Map的成员数
clear()清除Map所有成员,没有返回值
let data2 = new Map()let s2 = {   name : "艺术概论" }data2.set(s2,"中国工艺美术史")data2.size; // 1data2.has(s2);  // treudata2.delete(s2); // truedata2.has(s2); // falsedata2.clear(); // undefined

Map参数

Map可以接收数组作为参数,数组的成员是单个单个键值对的数组

let map = new Map([     ["name","东方不败"],     ["title","西方求败"]])console.log(map.size);  // 2console.log(map);  // {"name" => "东方不败"}, {"title" => "西方求败"}console.log(map.has("name")); // trueconsole.log(map.get("name")); // 东方不败

注意:如果有多个相同的键,后面的键值会覆盖前面的键值

不仅是数组,任何具有Iterator接口、且每个成员都是一个双元素的数组的数据结构,都可以当做Map构造函数的参数,SetMap也可以用来生成新的Map

Set作为参数

let set = new Set([["a",1],["b",2]])let m = new Map(set)console.log(m); // {"a" => 1, "b" => 2}console.log(m.get("a")); // 1

Map作为参数

let map2 = new Map([["text","世界现代设计史"],["name","王受之"]])let m2 = new Map(map2)console.log(m2); // {"text" => "世界现代设计史", "name" => "王受之"}console.log(m2.get("text")); // 世界现代设计史console.log(m2.get("hello")); // 读取不存在的键会返回undefined

Map只有对同一个对象的引用才视为同一个键

let map3 = new Map()map3.set(["a",100])console.log(map3.get(["a"])); // undefined

因为数组不是引用类型,生成多个数组,它们的内存地址是不一样的,其实就是基础数据类型和引用数据类型的应用,这里的两个["a"]看似是一样的,其实它们根本就是两个不同的值,Map只有对同一个对象的引用才视为同一个键,没有读取到所以返回undefined。请看下面的例子

let map4 = new Map()let b = ["b"]let b2 = ["b"]map4.set(b)console.log(map4.get(b2)); // undefined

Map的值其实是跟内存地址绑定的,内存地址不同,那么键就不同(即使名字一模一样),在这里Map就解决了同名属性冲突的问题,当我们使用别人的库时,使用对象名当做键,就不同担心自己的属性与别人的属性相同了。

如果Map的键是一个简单数据类型的值,如:number、string、boolean,只要这两个值严格相等,Map就视为同一个键,例如:0-0就是同一个键,而布尔值true和字符串true就是不同的键,此外nullundefined也是不同的键。NaN视为同一个键。

let n = new Map()n.set(0,100)console.log(n.get(-0)); // 100n.set(5,123)console.log(n.get("5"));  // undefinedn.set(true,100)console.log(n.get(1)); // undefinedn.set(NaN,123)console.log(n.get(NaN)); // 123n.set(null,100)console.log(n.get(null)); // 100console.log(n.get(undefined)); // undefined

Map遍历方法

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

方法说明
Map.prototype.keys()返回键名的遍历器。
Map.prototype.values()返回键值的遍历器。
Map.prototype.entries()返回所有成员的遍历器。
Map.prototype.forEach()遍历 Map 的所有成员。

定义数据

let m3 = new Map([       ["a",100],       ["b",200],       ["c",300]])

keys

/* keys */for(let k of m3.keys()){   console.log(k);  // a  b  c}

values

/* values */for(let k of m3.values()){   console.log(k); // 100  200  300}

entries

for(let k of m3.entries()){    console.log(k); // ["a", 100]  ["b", 200]  ["c", 300]    console.log(k[0],k[1]); // a 100     b 200    c 300}// 或for(let [k,v] of m3.entries()){   console.log(k,v); // a 100     b 200    c 300}

forEach

m3.forEach(el => console.log(el))  // 100  200  300m3.forEach((val,index) => console.log(val,index))  // 100 "a"   200 "b"   300 "c" 

Map数据结构转换

Map转数组

使用扩展运算符将Map结构转换为数组

let a = new Map([      ["a",1],      ["b",2],      ["c",3]])console.log([...a.keys()]);  // ["a","b","c"]console.log([...a.values()]); // [1,2,3]console.log([...a.entries()]); // ["a", 1]  ["b", 2]  ["c", 3]console.log([...a]); // ["a", 1]  ["b", 2]  ["c", 3]

转换后的数组是一个真正的数组,可以使用数组方法

let back = [...a].filter((val,index) => val[1] == 2 )console.log(back); // ["b",2]

数组转Map

let a2 = new Map([       ["name","东方不败"],       [{num : 3},["abc"]]])console.log(a2); // 0: {"name" => "东方不败"}    1: {Object => Array(1)}

Map转对象

let a3 = new Map().set("a",100).set("b",200)/* 通过函数传入map */function mapToObj(mapVal){// 在内部创建一个空对象let obj = {}// 遍历map结构,给空对象赋值for([k,v] of mapVal){      obj[k] = v  }    return obj}let mObj = mapToObj(a3)console.log(mObj); // {a: 100, b: 200}

如果有非字符串键名,会被转换成字符串再创建对象键名

对象转Map

let obj = {"a":123,"b":456}       let mObj2 = new Map(Object.entries(obj))       console.log(mObj2);  // {"a" => 123, "b" => 456}

Map转JSON

Map转JSON需要区分两种情况1、Map键名都是字符串2、Map键名有非字符串的情况

1、Map键名都是字符串可以写一个通用函数,用来将Map转为JSON

let j = new Map().set("name","东方").set("text","不败")// mapToObj为上面创建的Map转对象的函数let shiftStrJson = (mapVal) => JSON.stringify(mapToObj(mapVal))console.log(shiftStrJson(j)); // "{"name":"东方","text":"不败"}"

2、Map键名有非字符串的情况

function shiftMaptoArrayJson(mapVal){     return JSON.stringify([...mapVal])}let j2 = new Map().set("name","东方").set("text","不败")let shiftStrJson2 = shiftMaptoArrayJson(j2)console.log(shiftStrJson2);  // "[["name","东方"],["text","不败"]]"

以上两种的转换结果:

JSON转Map

JSON转Map需要区分两种情况1、Map键名都是字符串2、Map键名有非字符串的情况

1、键名都是字符串

let strObj = "{"name":"东方","text":"不败"}"let strMap = new Map(Object.entries(JSON.parse(strObj)))console.log(strMap); // {"name" => "东方", "text" => "不败"}

2、键名有非字符串情况

let strObj2 = "[["name","东方"],["text","不败"]]"let strMap2 = new Map(JSON.parse(strObj2))console.log(strMap2); // {"name" => "东方", "text" => "不败"}

案例源码:https://gitee.com/wang_fan_w/es6-science-institute

如果觉得这篇文章对你有帮助,欢迎点亮一下star哟

关键词: 东方不败 数据结构 工艺美术