Object是最常用的引用类型数据,可用于存键值对的集合,在ECMAScript 第一个版本里添加的
Map是专属键值对的集合,采用Hash结构存储,在ECMAScript 2015(Es6)中添加的
共同点: 键值对的动态集合,支持增加和删除键值对
不同点:
- 键的类型
/** * 1. 键的类型 * Object * - 键值必须是String或者Symbol,否则会进行数据类型的转换 * Map * - 键可以是任意类型,包括对象、数组、函数等,不会进行类型转换,在添加键值对时,会通过严格相等(===)来判断属性是否已经存在 */ const obj = {a: 1} const arr = [1, 2] obj[arr] = 'arr' console.log(obj) // {a: 1, 1,2: 'arr'} const map = new Map() map.set('a', 1) map.set(2, 2) map.set(arr, 'arr') console.log(map) //{'a' => 1, 2 => 2, Array(2) => 'arr'} // 特例 // NaN === NaN ==> false const map2 = new Map() map2.set(NaN, 1) map2.set(NaN, 2) console.log(map2) // {NaN => 2}
-
键的顺序
/** * 2. 键的顺序 * Object * - key是无序的,不会按照添加的顺序返回 * - 1.对于大于0的整数,会按照大小进行排序;对于小数和负数会当字符串处理 * - 2.对于String类型,按照定义的书序输出 * - 3.对于Symbol类型,会直接过滤掉,不进行输出 * - 如果想输出Symbol类型,通过Object.getOwnPropertySymbols()方法 * * Map * - key是有序的,按照插入的顺序进行返回 */ const obj2 = { 2: 2, '1': 1, 'b': 'b', 1.1: 1.1, 0: 0, 'a': 'a', [Symbol('s1')]: 's1', [Symbol('s2')]: 's2' } console.log(obj2) // {0: 0, 1: 1, 2: 2, b: 'b', 1.1: 1.1, a: 'a', Symbol(s1): 's1', Symbol(s2): 's2'} console.log(Object.keys(obj2)) // ['0', '1', '2', 'b', '1.1', 'a'] const map3 = new Map() map3.set(2, 1) map3.set('1', 1) map3.set('b', 'b') map3.set(0, 0) map3.set('a', 'a') map3.set(Symbol('s1'), 's1') console.log(map3.keys()) // {2, '1', 'b', 0, 'a', Symbol(s1)}
-
键值对size
/** * 3. 键值对size * Object * - 只能手动计算,通过Object.keys()方法,或者通过for...in 循环统计 * * Map * - 直接通过size属性访问 * */ const obj3 = { 'q': 1, 'w': 2, 'e': 3 } console.log(Object.keys(obj3).length) // 3 const map4 = new Map() map4.set('q', 1) map4.set('w', 2) map4.set('e', 3) console.log(map4.size) // 3
-
键值对的访问
/** * 4. 键值对的访问 * Object * - 判断属性是否存在(undefined) * * Map * - 判断属性是否存在(has) */ const obj4 = { name: 'Bulala', age: 18 } console.log(obj4.name === undefined) // false const map5 = new Map() console.log(map5.has('name')) // false
-
迭代器(for...of)
/** * 5. 迭代器(for... of) * Object * - Object本身是不具备Iterator特性的,不能使用for.. if进行遍历 * * Map * - Map结构的keys(), values(), entries()方法返回值都具有Iterator特性, 可以使用for.. if进行遍历 */ const obj5 = { name: 'Bulala', age: 18 } // for(let key of obj5) { // console.log(key) // 报错:Uncaught TypeError: obj5 is not iterable // } const map6 = new Map([ ['name', 'Bulala'], ['age', 18] ]) for(let key of map6.entries()) { console.log(key) // ['name', 'Bulala'] ['age', 18] }
-
JSON序列化
/** * 6. JSON序列化 * Object * - Object类型可以通过JSON.stringify()进行序列化操作 * * Map * - Map结构不能直接进行序列化 */ const obj6 = { name: 'Bulala', age: 18 } console.log(JSON.stringify(obj6)) // {"name":"Bulala","age":18} const map7 = new Map([ ['name', 'Bulala'], ['age', 18] ]) console.log(JSON.stringify(map7)) // {} // 不能直接序列化,得先转成数值,在进行序列化 console.log(JSON.stringify(Array.from(map7))) // [["name","Bulala"],["age",18]]
总结:
类型 适用场景 Object 1. 仅做数据存储,并且属性值仅为字符串或Symbol
2. 需要进行序列化转换为JSON时
3. 当做一个对象的实例,需要保留自己的属性和方法时
Map 1. 频繁更新和删除键值对时
2. 存储大量数据时,尤其是key类型未知的情况下
3. 需要频繁进行迭代处理
若有不足之处望大家指教,后续其他内容会继续补充。