javascript的对象(Object)本质上是键值对的集合,只能用字符串作为键名,对于其他的类型,会自动转为字符串:
let array_ = [1, 2, 3, 4];//数组
let function_ = function () {};//函数
let number_=123;//数字
let object_={};//对象
let a = {};
a[number_]="q";
a[array_]="qe";
a[function_]="qwe";
a[object_]="qwer";
let p = Object.keys(a);
console.log(p);//["123","1,2,3,4","function(){}","[object object]"]
console.log(typeof p[0]);//string
console.log(typeof p[1]);//string
console.log(typeof p[2]);//string
console.log(typeof p[3]);//string
为了解决这个问题ES6提供了Map数据结构,它类似对象,也是键值对的集合,但是键名可以是各种类型:
let number_=123;//数字
let array_ = [1, 2, 3, 4];//数组
let function_ = function () {};//函数
let object_={};//对象
const a=new Map();
a.set(number_,"q");
a.set(array_,"qw");
a.set(function_ ,"qwe");
a.set(object_,"qwer");
a.get(number_);//q
a.get(array_);//qw
a.get(function_);//qwe
a.get(object_);//qwer
for(let key of a.keys()){
console.log(typeof key);
}
//number
//object
//function
//object
上面用到了Map结构的get和set操作方法。
任何具有Iterator接口,且每个成员都是一个双元素数组的数据结构都可以当作Map构造函数的参数。例如数组:
const map = new Map([
[1,"one"],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => "one",
// 2 => "two",
// 3 => "three"
// }
如果传入的数组成员是存在三个元素的数组,则会忽略第三个元素:
const map = new Map([
[1,"one","_one"],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => "one",
// 2 => "two",
// 3 => "three"
// }
数组的成员存在单元素数组:
const map = new Map([
[1],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => undefined,
// 2 => "two",
// 3 => "three"
// }
除了数组,Map和Set都可以用来生成新的Map。
const map=new Map();
//虽然k1和k2的值是相同的,但k1和k2存储的内存地址是不同的
const k1=["a"];
const k2=["a"];
map.set(k1,111)
.set(k2,111);
map.get(k1);// 111
map.get(k2);// 222
Map的键与内存地址绑定,只要两个值的内存地址不同,Map就将它们视为两个键。
size属性返回Map结构的成员总数
let a=new Map();
a.set("1","q");
a.set("2","qw");
console.log(a.size)//2
set方法设置键名(key)对应的键值(value),返回Map结构。如果设置的key已经有值,则键值会被更新。由于set方法返回的是当前的Map对象,因此可以采用链式写法:
let a=new Map();
a.set("1","q")
.set("2","qw")
.set("3","qwe");
get方法读取key所对应的键值,如果找不到key,返回undefined。
has方法返回一个布尔值,表示某个键是否存在Map中。
delete方法删除某个键,返回true。如果删除失败,返回false。
clear方法清除所有成员,没有返回值。
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 item of map.entries()) {
console.log(item[0],item[1]);
}
//"F" "NO"
//"T" "YES"
//或者
for (let [key,value] of map.entries()) {
console.log(key,value);
}
//"F" "NO"
//"T" "YES"
//和使用map.entries()相同
for (let [key,value] of map) {
console.log(key,value);
}
//"F" "NO"
//"T" "YES"
Map结构的默认遍历器属性接口(Symbol.iterator属性)就是entries方法(在Set结构中默认遍历器生成函数是它的values方法)。
Map结构转为数组结构的比较快速的方法是结合扩展运算符(…)。
const map = new Map([
["1", "one"],
["2", "two"],
["3", "three"]
]);
console.log([...map.keys()]);
//["1","2","3"]
console.log([...map.values()]);
//["one","two","three"]
console.log([...map.entries()]);
//[["1","one"],["2","two"],["3","three"]]
console.log([...map]);
//[["1","one"],["2","two"],["3","three"]]
Map本身没有map和filter方法,但是可以结合数组的map方法、filter方法,可以实现Map的遍历和过滤。
const map = new Map([
[1, "one"],
[2, "two"],
[3, "three"]
]);
const map1=new Map(
[...map].filter(([k,v])=>k<3)
);
//产生map结构 {1=>"one",2=>"b"}
const map2=new Map(
[...map].map(([k,v])=>[k*2,"_"+v])
);
//产生map结构 {2=>"_one",4=>"_two",6=>"_three"}
Map的forEach方法与数组的forEach方法类似,可以实现遍历。
const map = new Map([
[1, "one"],
[2, "two"],
[3, "three"]
]);
map.forEach(function (value, key, map) {
console.log("Key:%s,Value:%s", key, value);
});
// Key:1,Value:one
// Key:2,Value:two
// Key:3,Value:three
forEach方法还可以接受第二个参数,用于绑定this。
const map = new Map([
[1, "one"],
[2, "two"],
[3, "three"]
]);
const reporter={
report:function(key,value){
console.log("Key:%s,Value:%s", key, value);
}
};
map.forEach(function (value, key, map) {
this.report(key,value);
},reporter);
// Key:1,Value:one
// Key:2,Value:two
// Key:3,Value:three
Map转为数组最方便的方法就是使用扩展运算符(…)(这里的例子和前面的例子相同)
const map = new Map([
["1", "one"],
["2", "two"],
["3", "three"]
]);
console.log([...map.keys()]);
//["1","2","3"]
console.log([...map.values()]);
//["one","two","three"]
console.log([...map.entries()]);
//[["1","one"],["2","two"],["3","three"]]
console.log([...map]);
//[["1","one"],["2","two"],["3","three"]]
将数组传入构造函数就可以转为Map。
const map = new Map([
[1,"one"],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => "one",
// 2 => "two",
// 3 => "three"
// }
const map = new Map([
[1],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => undefined,
// 2 => "two",
// 3 => "three"
// }
const map = new Map([
[1,"one","_one"],
[2, "two"],
[3, "three"]
]);
// Map{
// 1 => "one",
// 2 => "two",
// 3 => "three"
// }
如果Map的所有键都是字符串,则可以转为对象。
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k, v] of strMap) {
obj[k] = v;
}
return obj;
}
const myMap = new Map()
.set('yes', true)
.set('no', false)
let a = strMapToObj(myMap);
console.log(a)
// { yes: true, no: false }
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
let a=objToStrMap({yes: true, no: false});
console.log(a)
// Map {"yes" => true, "no" => false}
将Map转为对象,之后调用JSON.stringify()转化为对象JSON:
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.stringify()转化为数组JSON:
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
调用JSON.parse()将对象JSON(所有键名都是字符串)转为对象,之后将对象转为Map。
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
调用JSON.parse()将数组JSON转为数组,之后将数组传入Map的构造函数。
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
数组成员存在三个元素的数组,则忽略第三个元素:
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7,8],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
数组成员存在单元素的数组:
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true],[{"foo":3},["abc"]]]')
// Map {true => undefined, Object {foo: 3} => ['abc']}
参考文献:《ECMAScript 6 入门》阮一峰