ES6新增数据类型之Map、WeakMap

135 阅读4分钟

1、Map

img

在ES6以前,在js中实现 键/值式 存储可以使用 Object 来高效完成,ES6新增了一种新的集合类型 Map

它最大的特点就是:Map中键的范围不限于字符串类型,各种类型的值(包括对象)都可以当做是一个键或一个值

所以ObjectMap 键值对类型:

  • Object字符串/Symbol类型: 任意类型
  • Map任意类型: 任意类型

1.1 基本的API

1、创建一个空Map

// 必须是以这种方式创建
let map= new Map();

2、初始化Map

Map构造函数传入一个可迭代对象,需要包含键值对,每个键值对会按照迭代顺序映射到实例当中

const map = new Map([
	['name', 'cyf'],
    ['age', 18]
]);
console.log(map);  // {"name" => "zxc", "age" => 18}

3、Map常用方法

方法说明示例
get()通过键来获取值,如果没有该键,则返回 undefinedmap.get('name')
has()判断是否有该键,返回布尔值map.get('name')
set()用于设置对应的键值对,若有相同会覆盖map.set('name', 'zxc')
delete()用于删除某个键,成功则返回true,失败返回falsemap.deldect('name')
clear()用于清空 Map() 中所有的成员,没有返回值map.clear()
let map = new Map([
    ['namer', '张三'],
    ['age', 2]
]);

// 获取namer
console.log(map.get('namer')); // 张三

// 判断namer
console.log(map.has('age')); // 2

// 设置键值对
console.log(map.set('sex', '其它')); // { 'namer' => '张三', 'age' => 2, 'sex' => '其它' }
console.log(map.set('id', 0).set('hobby', '讲段子'));

// size属性,获取map长度
console.log(map.size); // 5

// 删除某个键
console.log(map.delete('id')); // true

// 清空map
map.clear()
console.log(map); // {}

1.2 顺序与迭代

Object 类型的一个差异是:Map 实例会维护键值对的插入顺序,因此可以根据顺序执行迭代操作

Map 提供了3个遍历器和一个遍历方法

方法说明示例
keys()返回键的遍历器map.key()
values()返回值的遍历器map.value()
entries()返回所有成员的遍历器,包含键,值map.entries()
forEach遍历Map的所有成员map.forEach(function(), [this])
let map = new Map().set('namer', '张三').set('age', 2).set('sex', '其它')

// 获取键
let keys = map.keys()
console.log(keys);

// 获取值
let values = map.values()
console.log(values);

// 获取键值对
console.log(map.entries());  // { [ 'namer', '张三' ], [ 'age', 2 ], [ 'sex', '其它' ] }

for (let [key, value] of map) {
    console.log(key + ':' + value);
}
// namer:张三
// age:2
// sex:其它

// forEach 循环
map.forEach(function(value, index) {
    console.log(index + ':' + value);
})

// namer:张三
// age:2
// sex:其它

1.3 MapObject的区别

1、键名类型

  • Object 只能接收两种类型的键名:StringSymbol
  • Map 能够接受任意类型的键名

Map 键名:

let map = new Map();
map.set(1, 'Number').set(true, 'Boolean').set({ '键名': '键值' }, 'Object').set(function() {}, 'Function')
console.log(map);  
// { 1 => 'Number', true => 'Boolean', { '键名': '键值' } => 'Object', [Function (anonymous)] => 'Function'}

Object键名

let obj = {}
obj[1] = 'Number';
obj[true] = 'Boolean';
obj[{ '键名': '键值' }] = 'Object';
obj[function() {}] = 'Function'

console.log(obj);
// { '1': 'Number', true: 'Boolean', '[object Object]': 'Object', 'function() {}': 'Function' }

虽然说Object 可以接受其他类型的键名,当时js都会隐式地将其转换为字符串

2、迭代

  • Map 是可以迭代的,用 forEach循环或 for...of
  • Object 是不能直接进行迭代的

Object 遍历需要借助对象的静态方法

let obj = { 'namer': '张三', 'age': 2, 'sex': '其它' }

// 遍历键
for (let key of Object.keys(obj)) {
    console.log(key);
}

还可以是:

for (let value of Object.values(obj)) {}

for (let keyValue of Object.entries(obj)) {}

for (let [key, value] of Object.entries(obj)) {}

当然可以使用 for...in 遍历键

for (let key in obj) {
    console.log(key); // namer age sex
}

3、顺序和长度

长度

  • Map保存对长度的跟踪,可直接使用size,其时间事件复杂度为 O(1)
  • 对于 Object而言,想要获取对象长度需要对于其进行迭代,其时间复杂度为 O(n)

顺序

  • Map 始终是保持键值对插入时的顺序
  • Object则不是,不过ES6之后就会可以按顺序保存了,只是通过隐式转换为字符串的键就乱序了

总结:

  1. Map的键可以是任意类型,并且可以用 forEach 等迭代
  2. Map 的键值对是根据set设置的顺序存储的
  3. Map 获取长度就是用size属性直接返回,时间复杂度为 O(1)
  4. Map 缺点就是不能使用 [] 来设置和获取键值,只能用setget 来代替
  5. 固定大小内存,Map 大约可以比Object 多存储50%的键值对

2、weakMap

img

weakMapMap的变体,它们的方法基本是一样的,区别在于内部分配的工作方式

weakMap 只接受引用类型的数据作为键名,如:数组、函数、对象等

2.1 基本API

1、创建一个空的WeakMap

let WeakMap = new WeakMap();

2、初始化WeakMap

let weakMap = new WeakMap();
let x = { id: 1 },
    y = { id: 2 }
weakMap.set(x, '张三')
weakMap.set(y, 2)

console.log(weakMap.get(x)); // 张三
console.log(weakMap.get(y)); // 2

console.log(weakMap.has(x)); // true
console.log(weakMap.delete(x));  // true

WeakMap 中没有clear方法 和 size属性