众所周知 JavaScript 的 Object 和 Map 这两种数据结构很相似,
但深究底层原理来看,这两者本质上还是存在了不少差异,通过区别比较能帮助我们更好地理解它们的用处和使用场景。
键类型
Object
Object 的键必须是 String 或 Symbol 类型,并默认调用 toString 方法将键转化为 String 类型,因此可能会存在同名键覆盖问题。
注:
Array和Function本质是对Object的继承,因此都有对应的toString方法。
对象键
将对象作为键时会调用 Object.toString 方法将其转化为对象字符串 ("[object Object]")。
({}.toString()); // "[object Object]"
var obj = {};
obj[{}] = "ok";
console.log(JSON.stringifpwdy(obj)); // {"[object Object]":"ok"}
数组键
将数组作为键时会调用 Array.toString 方法将其转化为空字符串 ("")。
[].toString(); // ""
var obj = {};
obj[[]] = "ok";
console.log(JSON.stringify(obj)); // {"":"ok"}
函数键
将函数作为键时会调用 Function.toString 方法将其转化为函数字符串 ("() => {}")。
(function test() => {}).toString(); // "() => {}"
var obj = {};
obj[() => {}] = "ok";
console.log(JSON.stringify(obj)); // {"() => {}":"ok"}
Map
Map 支持任意类型的键。
Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values.
键唯一性
Object 同名键覆盖
由于 Object 的键默认会调用 toString 方法,因此当前键如果是空对象({})或者空数组([])的话,多次赋值会出现被覆盖的情况。
var obj = {};
obj[{}] = "step1";
obj[{}] = "step2";
console.log(JSON.stringify(obj)); // {"[object Object]":"step2"}
Map 唯一键
在 Map 中每个键都是唯一的,在存储过程中 Map 会对存入键的 类型 或 引用 进行比较。假设当前 Map 存入了两个空对象({}),两者类型相同,但在 栈 中引用的内存地址不同,那么 Map 就会认定为是两个独立键,示例如下:
遍历次序
Object 无序
在遍历 Object 后得到的结果是一个无序列表。
var obj = { 1: 1, 2: 2, a: "a", f: "f" };
console.log(Object.keys(obj)); // ["1", "2", "a", "f"]
obj = { a: "a", 1: 1, 2: 2, f: "f" };
console.log(Object.keys(obj)); // ["1", "2", "a", "f"]
Map 有序
在遍历 Map 后得到的结果是一个有序列表。
var map = new Map();
map.set(1, 1);
map.set("a", "a");
map.set(2, 2);
console.log([...map.values()]); // [1, "a", 2]
可遍历
Object
Object 没有实现遍历器(@@iterator)接口,无法使用 for of 遍历,但可以用 for in 等方法遍历。当然,Object 原生不支持但可以扩展 @@iterator 实现遍历,详见 iterator。
var obj = { a: "a", 1: 1, 2: 2, f: "f" };
for (key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key);
}
}
console.log(Object.keys(obj)); // ["1", "2", "a", "f"]
Map
Map 内部实现了遍历器(@@iterator)接口,可以使用 for of 遍历。
Map.prototype @@iterator
var map = new Map();
map.set(1, 1);
map.set("a", "a");
map.set(2, 2);
for (item of map) {
console.log(item);
}
继承关系
从原型链继承结构中,我们可以看到 Map 底层实际上是继承自 Object ,即 Map 是 Object 的实例对象,反之 Object 并不是 Map 的实例对象。




Top comments (0)