本文内容
- Map 的基本使用
- Map 支持的数据类型
- Map 的迭代
- Map 与其他对象的转化
在 Map 出现之前,要实现类似需求,只能使用 Object,但是 Object 还是存在一些问题的。
- 如果使用 Object 作为 key 存储在 {} 中,key 最终是当做
[object Object]
来使用的 - Object 的 keys 是无序的
- 无法安全遍历 Object
- 无法直接获取 Object 大小
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
基本操作
new Map([iterator])
- iterator <Iterator> 可以是一个数组或者其他 iterator 对象,其元素为键值对(如
['key', 'value']
)。 - null 或 undefined 不会生效,返回一个空的 Map
- 非 iterator 会抛出错误
TypeError: object is not iterable
const map = new Map();
// Create
map.set('name','xialei');
map.set('site', 'https://www.ddhigh.com');
// Update
map.set('name', 'xialeistudio');
// Read
map.get('name');
// Delete
map.delete('name');
// 清空
map.clear();
// map 大小
console.log(map.size);
数据类型测试
JS 中基本数据类型有 string、number、boolean、null、undefined、symbol,复杂数据类型有 object(包括 object,array,function 等),还有个特殊的 NaN(typeof 结果是 number),分别对这些类型进行测试
const map = new Map();
const sKey = 'key',
nKey = 1,
bKey = true,
nullKey = null,
uKey = undefined,
symbolKey = Symbol("key"),
oKey = {},
ooKey = oKey,
aKey = [],
fKey = function () {},
nanKey = NaN;
map.set(sKey, "string")
.set(nKey, "number")
.set(bKey, "boolean")
.set(nullKey, "null")
.set(uKey, "undefined")
.set(symbolKey, "symbol")
.set(oKey, "object")
.set(aKey, "array")
.set(fKey, "function")
.set(nanKey, "NaN");
console.log(map);
console.log(map.get(sKey) === "string", map.get("key") === "string");
console.log(map.get(nKey) === "number", map.get(1) === "number");
console.log(map.get(bKey) === "boolean", map.get(true) === "boolean");
console.log(map.get(nullKey) === "null", map.get(null) === "null");
console.log(map.get(uKey) === "undefined", map.get(undefined) === "undefined");
console.log(map.get(symbolKey) === "symbol");
console.log(map.get(oKey) === "object", map.get({}) === "object", map.get(oKey) === map.get(ooKey));
console.log(map.get(aKey) === "array", map.get([]) === "array");
console.log(map.get(fKey) === "function", map.get(function () {}) === "function");
console.log(map.get(nanKey) === "NaN", map.get(NaN) === "NaN");
输出如下
Map {
'key' => 'string',
1 => 'number',
true => 'boolean',
null => 'null',
undefined => 'undefined',
Symbol(key) => 'symbol',
{} => 'object',
[] => 'array',
[Function: fKey] => 'function',
NaN => 'NaN'
}
true true
true true
true true
true true
true true
true
true false true
true false
true false
true true
结论
- string/number/boolean/null/undefined/NaN 按值存储,值一致即可访问
- symbol 必须是同一个 Symbol 才能访问,详见深入浅出 ES6 的 Symbol 类型
- object/array/function 等 Object 类型按照引用访问,必须是同一个引用才可以访问
- Map 是
有序
的,按照插入顺序 - Map.set 方法支持链式操作
Map 的迭代
for…of
同时迭代键值
// 普通版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const [k, v] of map) {console.log(k, v);
}
// 迭代器版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const [k, v] of map.entries()) {console.log(k, v);
}
迭代键
// 普通版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const k of map.keys()) {console.log(k, map.get(k));
}
// 迭代器版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const [k] of map.entries()) { // 解构赋值
console.log(k, map.get(k));
}
迭代值
// 普通版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const v of map.values()) {console.log(v);
}
// 迭代器版本
const map = new Map();
map.set("1", 1);
map.set("2", 2);
for (const [,v] of map.entries()) {console.log(v);
}
forEach()
forEach 方法的顺序是 value, key,不是 key, value!
const map = new Map();
map.set("1", 1);
map.set("2", 2);
map.forEach((value, key) => {console.log(value, key);
});
Map 与其他类型的转换
Map 与 Object
const obj = {
name: 'xialei',
site: 'https://www.ddhigh.com'
};
const map = new Map(obj);
console.log(map);
执行报错TypeError: object is not iterable
,因为 Object 不是可迭代对象。
可迭代对象:ES6 新出的语法,对象或对象的原型链实现了 Symbol.iterator 方法,关于迭代器的内容将在下一篇文章中详细介绍
我们给 Object.prototype 添加属性方法来支持迭代:
warning: 正式代码请谨慎修改原型链!
const obj = {
name: 'xialei',
site: 'https://www.ddhigh.com'
};
Object.prototype[Symbol.iterator] = function () { // Symbol.iterator 可以理解为全局唯一的标识
const keys = Object.keys(this);
let keyIndex = 0;
return {next() {if (keyIndex < keys.length) {const key = keys[keyIndex++];
return {value: [key, obj[key]] }; // 迭代值
}
return {done: true}; // 迭代结束
}
}
};
const map = new Map(obj);
console.log(map);
Map 与数组
只支持 [[key, value]] 这种二维数组。二维数组的每一个元素包含 key 和 value 两个子元素
const map = new Map([['name', 'xialeistudio'], ['site', 'https://www.ddhigh.com']]);
Map 与 Map
由于 Map 是可迭代对象,因此可以作为参数传给 Map 构造函数
两个 Map 的元素是一样的,不是 Map 不相等,因为不是同一个对象
const map = new Map([['name', 'xialeistudio'], ['site', 'https://www.ddhigh.com']]);
const map2 = new Map(map);
console.log(map === map2); // false
Map 的合并
多个 Map 可以合并,相同 key 会被覆盖,规则为后面的覆盖前面的
const map = new Map([[1, 1],
[2, 2]
]);
const map2 = new Map([[1, 2]
]);
const map3 = new Map([...map, ...map2]);
console.log(map3); // Map {1 => 2, 2 => 2}
总结
Map 的出现解决了传统 object 无法直接解决的问题,更好地向标准编程语言靠近 (标准编程语言一般会提供 Map 集合),使用的坑也比较少(比如没有 object 作为 key 时转换为[object Object] 的问题)。
更多原创文章,尽在每天进步一点点