我们经常需要做键值对存储,大多时候我们会选择对象字面量Object ({}) 来存储,往往会忽略ES6 新提供的数据结构:Map。从字面上来看,Map才是正确的选择。
接下来我们一起来比较一下对象字面量 和 Map 的差别。
基本使用
添加键值对,访问键值操作。
Object
// init
const keyValue = {}
// add
keyValue['firstname'] = 'tony'
// get
keyValue['firstname']
Map
// init
const keyValue = new Map()
// add
keyValue.set('firstname', 'tony')
// get
keyValue.get('firstname')
当访问对象未定义的属性或键时,都会访问undefined
const o = {}
o['firstname'] // undefined
const m = new Map()
m.get('firstanme') // undefined
迭代
键值对也经常需要进行遍历操作。Map 数据类型本身是可迭代的,内置forEach方法:
const kv = new Map()
kv.set('firstname', 'tony')
kv.set('lastname', 'stark')
kv.forEach((value, key) => console.log(key, value))
// firstname tony
// lastname stark
Object没有forEach方法,你可以使用 for … in :
{id: 1, name: "test"}
for (var key in obj){
console.log(`key: ${key}, value: ${obj[key]}`);
//key: id, value: 1
//key: name, value: test
}
也可以通过内置的迭代器:entries(), values(), keys() 生成可迭代的数据。
const kv = {}
kv['firstname'] = 'tony'
kv['lastname'] = 'stark'
Object.keys(kv).forEach((key) => console.log(key, kv[key]))
// firstname tony
// lastname stark
或者
Object.entries(kv).forEach((entry) => console.log(entry[0], entry[1]))
// firstname tony
// lastname stark
相比之下,Map 的迭代操作更简单,可读性更好一些。
检查是否存储某键值
const kv = new Map()
kv.set('firstname', 'tony')
kv.set('lastname', 'stark')
kv.has('firstname') // true
kv.has('nickname') // false
以上 Map 操作很简单,以下 Object 相对复杂:
const kv = {}
kv['firstname'] = 'tony'
kv['lastname'] = 'stark'
Object.prototype.hasOwnProperty.call(kv, 'firstname') // true
Object.prototype.hasOwnProperty.call(kv, 'nickname') // false
查看键值对数量
Map有内置的size属性
const kv = new Map()
kv.set('firstname', 'tony')
kv.set('lastname', 'stark')
kv.size // 2
Object 需要先生成一个可迭代集合。
const kv = {}
kv['firstname'] = 'tony'
kv['lastname'] = 'stark'
Object.keys(kv).length // 2
其它细节
1 Object 对象字面量的键只能是string类型,但Map的键可以是任何类型。
const m = new Map()
m.set(['a', 'b'], true)
m.set(['a', 'c'], false)
但Object 对象字面量,如果输入一个数值,也会转化成字符串。
const o = {}
o[1] = 'iron man'
o[1] // 'iron man'
o['1'] // 'iron man'
2 Object对象拥有原型prototype,意味着它已内置一些键值,增加复杂度。
const o = {}
o['constructor'] // ƒ Object() { [native code] }
const m = new Map()
m.get('constructor') // undefined
3 JSON能够序列化Object ,无法序列化Map。
const kv = {}
kv['firstname'] = 'tony'
kv['lastname'] = 'stark'
JSON.stringify(kv) // '{"firstname":"tony","lastname":"stark"}'
而Map不行
const kv = new Map()
kv.set('firstname', 'tony')
kv.set('lastname', 'stark')
JSON.stringify(kv) // '{}'
所以涉及到转化成json进行http传输时,Map不是好的选择。
Object vs Map 你到底选谁?
在我看来,只要你不需要序列化数据,任何键值对都应该用Map 来存储。
Map可以不局限于string,可以存储任意类型键值。同时有has() size等方法的方法属性。
Object 适用于复杂的对象,比如具有一定的函数方法:
const ironman = {
firstname: 'tony',
lastname: 'stark',
hello: function() {
return `I am ${this.firstname} ${this.lastname}`
}
}
参考资料