概述
- Object 是最常见的一种引用类型数据,可用于存储键值对的集合。
- Map 是键值对的集合,采用Hash结构存储,ES6新增。
Object
// 定义
const obj = {
a: 1,
b: 2
};
// 添加键值对
obj.c = 3;
// 删除键值对
delete obj.c;
Map
// 定义
const map = new Map();
// 添加键值对
map.set('a', 1);
map.set('b', 2);
// 删除键值对
map.delete('a');
共同点
键值对的动态集合,支持增加和删除键值对。
不同点
- 构造方式
/** object **/
// 对象字面量
const obj = {
'a': 1,
'b': 2
}
// 构造方法
const o = new Object();
const o2 = Object.create();
/** Map **/
// 构造方法
const m = new Map();
cosnt m2 = new Map([
['a', 1],
['b', 2]
]);
- 键的类型
/** object **/
键类型必须是String或者Symbol,如果是非String类型,会进行数据类型转换。
const obj2 = { a: 1};
const arr1 = [1, 2];
// 例1:
obj2[arr1] = 'arr';
console.log(obj2); => { a: 1, 1,2: 'arr'}
// 例2:
obj2[3] = 3;
obj2['3'] = 33;
console.log(obj2); => {3: 33, a: 1, 1,2: 'arr'}
/** Map **/
可以是任意类型,包括对象、数组、函数等,不会进行类型转换。在添加键值对时,会通过严格相等(===)来判断键属性是否已存在。
const map2 = new Map();
map2.set('a', 1);
map2.set('2', '2');
map2.set(2, 2);
map2.set(arr1, 1);
console.log(map2); => {'a' => 1, '2' => '2', 2 => 2, Array(2) => 1}
// 特例 NaN
console.log(NaN === NaN); => false
const map = new Map();
map.set(NaN, 1);
map.set(NaN, 2);
console.log(map); => {NaN => 2}
- 键的顺序
/** object **/
key是无序的,不会按照添加的顺序返回
1. 对于大于等于0的整数,会按照大小进行排序;对于小数和负数,会当做字符串处理。
2. 对于String类型,按照定义的顺序进行输出
3. 对于Symbol类型,会直接过滤掉,不会进行输出,如果想要输出Symbol类型属性,需要通过Object.getOwnPropertySymbol()方法
const obj3 = {
2: 2,
'1': 1,
'b': 'b',
1.1: 1.1,
0: 0,
'a': 'a',
[Symbol('s1')]: 's1'
}
console.log(Object.keys(obj3)); => ['0', '1', '2', 'b', '1.1', 'a']
/** Map **/
key是有序的,按照插入的顺序进行返回
const map3 = new Map();
map3.set(2, 2);
map3.set('1', 1);
map3.set('b', 'b');
map3.set(1.1, 1.1);
map3.set(0, 0);
map3.set('a', 'a');
map3.set(Symbol('s1'), 's1');
for(let key of map3.keys()) {
console.log(key); => 2, '1', 'b', 1.1, 0, 'a', Symbol(s1)
}
- 键值对size
/** object **/
只能手动计算,通过Object.keys()方法或者通过for...in循环统计
const obj4 = {
2: 2,
'1': 1,
'b': 'b'
}
console.log(Object.keys(obj4).length); => 3
/** Map **/
直接通过size属性访问
const map4 = new Map();
map4.set(2, 2);
map4.set('1', 1);
map4.set('b', 'b');
console.log(map4.size); => 3
- 键值对的访问
/** object **/
1. 添加或者修改属性,通过点或者中括号的形式
const obj5 = {};
obj5.name = 'sir';
obj5[Symbol('s5')] = 's5';
2. 判断属性是否存在
obj5.name === undefined;
obj5['name'] === undefined;
3. 删除属性,通过delete关键字
delete obj5.name;
/** Map **/
1. 添加和修改key-value
const map5 = new Map();
map5.set('name', 'sir');
map5.set(Symbol('s5'), 's5');
2. 判断属性是否存在
map5.has('name'); => true
map5.has('age'); => false
3. 取值
map5.get('name'); => 'sir'
4. 删除键值对
map5.delete('name');
5. 获取所有的属性名
map5.keys();
6. 清空map
map5.clear();
- 迭代器--for...of
/** object **/
Object本身不具有Iterator特性,默认情况下不能使用for...of进行遍历。
const obj6 = {
name: 'sir',
age: 28
}
for (let key of obj6) {} => Uncaught TypeError: obj6 is not iterable
/** Map **/
Map结构的keys(),values(),entries()方法返回值都具有Iterator特性
const map6 = new Map([
['name', 'sir'],
['age', 28]
]);
for(let [key, value] of map6.entries()) {
console.log(key, value); => name sir, age 28
}
- JSON序列化
/** object **/
Object类型可以通过JSON.stringify()进行序列化操作
const obj7 = {
name: 'sir',
age: 28
}
JSON.stringify(obj7); => '{"name":"sir","age":28}'
/** Map **/
Map结构不能直接进行JSON序列化
const map7 = new Map([
['name', 'sir'],
['age', 28]
])
JSON.stringify(map7); => '{}'
如果想要将map执行序列化操作,需要将其转换为数组
JSON.stringify(Array.from(map7)); => '[["name","sir"],["age",28]]'
- 应用场景
/** object **/
1. 仅做数据存储,并且属性仅为字符串或者Symbol
2. 需要进行序列化转换json传输时
3. 当做一个对象的实例,需要保留自己的属性和方法时
/** Map **/
1. 会频繁更新和删除键值对时
2. 存储大量数据时,尤其是key类型未知的情况下
3. 需要频繁进行迭代处理