在本教程中,您将了解将键映射到值的 JavaScript Map 对象。

JavaScript Map 对象简介

在 ES6 之前,我们经常使用对象来模拟映射 Map,将键映射到任意类型的值。但是使用对象作为映射有一些副作用:

  1. 对象总是有一个像原型一样的默认键。
  2. 对象的键必须是字符串符号,不能使用对象作为键。
  3. 对象没有表示映射大小的属性。

ES6 提供一个名为 Map 的新集合类型来解决这些缺陷。根据定义,Map 对象保存键值对。键在映射集合中是唯一的。换句话说,Map 对象中的键仅出现一次。Map 的键和值可以是任何值。

迭代 Map 对象时,每次迭代都会返回一个 [key, value] 成员数组。迭代顺序遵循插入顺序,插入顺序对应于 set() 方法每个键值对插入到 Map 的顺序。

要创建新的 Map,请使用以下语法:

let map = new Map([iterable]);

Map() 接受一个可选的可迭代对象,其元素是键值对。

JavaScript 映射方法

  • clear() – 从映射对象中删除所有元素。
  • delete(key) – 删除指定键的元素。如果该元素在映射中,则返回;如果不在,则返回 false。
  • entries()[key, value] – 返回一个新的 Iterator 迭代器对象,其中包含映射对象中每个元素的数组。映射中对象的顺序与插入顺序相同。
  • forEach(callback[, thisArg]) – 按插入顺序为映射中的每个键值对调用回调。可选的 thisArg 参数设置每个回调上下文。
  • get(key) – 返回与键关联的值。如果该键不存在,则返回未定义。
  • has(key) – 如果与该键关联的值存在,则返回 true,否则返回 false。
  • keys() – 返回一个新的迭代器,其中包含按插入顺序排列的元素的键。
  • set(key, value) – 设置映射对象指定键的值。它返回映射对象本身,因此您可以将此方法与其他方法链接起来。
  • values() 返回一个新的迭代器对象,其中包含按插入顺序排列的每个元素的值。

JavaScript 映射示例

让我们举一些使用 Map 对象的示例。

创建一个新的映射对象

假设您有一个 user 对象列表,如下所示:

let john = {name: 'John Doe'},
    lily = {name: 'Lily Bush'},
    peter = {name: 'Peter Drucker'};

假设您必须创建用户和角色的映射。在这种情况下,您使用以下代码:

let userRoles = new Map();

userRoles 是  Map 对象的实例,其类型是对象,如下例所示:

console.log(typeof(userRoles)); // object
console.log(userRoles instanceof Map); // true

将元素添加到映射

要将角色分配给用户,可以使用映射的 set() 方法:

userRoles.set(john, 'admin');

set() 方法将用户 johnadmin 角色进行映射。由于 set() 方法返回的是映射本身,因此您可以节省一些输入时间。如下例所示:

userRoles.set(lily, 'editor')
          .set(peter, 'subscriber');

使用可迭代对象初始化映射

如前所述,您可以将可迭代对象传递给 Map() 构造函数:

let userRoles = new Map([
    [john, 'admin'],
    [lily, 'editor'],
    [peter, 'subscriber']
]);

从映射获取指定键的值

如果你想查看 John 的角色,可以使用映射的 get() 方法:

userRoles.get(john); // admin

如果传递的键不存在,get() 方法将返回 undefined

let foo = {name: 'Foo'};
userRoles.get(foo); //undefined

通过键 key 检查元素是否存在

要检查映射中是否存在某个键,请使用映射的 has() 方法。

userRoles.has(foo); // false
userRoles.has(lily); // true

获取映射键值对的数量

映射 size 属性返回 Map 对象的键值对数量。

console.log(userRoles.size); // 3

迭代映射的键

要获取 Map 对象的键,可以使用 keys() 方法。keys() 返回一个新的迭代器对象,其中包含映射中元素的键。

以下示例展示 userRoles 映射对象的用户名。

let john = { name: 'John Doe' },
  lily = { name: 'Lily Bush' },
  peter = { name: 'Peter Drucker' };

let userRoles = new Map([
  [john, 'admin'],
  [lily, 'editor'],
  [peter, 'subscriber'],
]);

for (const user of userRoles.keys()) {
  console.log(user.name);
}

输出:

John Doe
Lily Bush
Peter Drucker

迭代映射值

同样,您可以使用 values() 方法获取映射中包含所有元素值的迭代器对象:

let john = { name: 'John Doe' },
  lily = { name: 'Lily Bush' },
  peter = { name: 'Peter Drucker' };

let userRoles = new Map([
  [john, 'admin'],
  [lily, 'editor'],
  [peter, 'subscriber'],
]);

for (let role of userRoles.values()) {
  console.log(role);
}

输出:

admin
editor
subscriber

迭代映射元素

此外,entries() 方法返回一个迭代器对象,其中包含 Map 对象中每个元素的数组 [key,value]

let john = { name: 'John Doe' },
  lily = { name: 'Lily Bush' },
  peter = { name: 'Peter Drucker' };

let userRoles = new Map([
  [john, 'admin'],
  [lily, 'editor'],
  [peter, 'subscriber'],
]);

for (const role of userRoles.entries()) {
  console.log(`${role[0].name}: ${role[1]}`);
}

为了使迭代更加简洁,可以使用解构赋值,如下所示:

let john = { name: 'John Doe' },
  lily = { name: 'Lily Bush' },
  peter = { name: 'Peter Drucker' };

let userRoles = new Map([
  [john, 'admin'],
  [lily, 'editor'],
  [peter, 'subscriber'],
]);

for (let [user, role] of userRoles.entries()) {
  console.log(`${user.name}: ${role}`);
}

除了for...of 循环之外,还可以使用 map 对象的 forEach() 方法:

let john = { name: 'John Doe' },
  lily = { name: 'Lily Bush' },
  peter = { name: 'Peter Drucker' };

let userRoles = new Map([
  [john, 'admin'],
  [lily, 'editor'],
  [peter, 'subscriber'],
]);

userRoles.forEach((role, user) => console.log(`${user.name}: ${role}`));

将映射键或值转换为数组

有时,您想使用数组而不是可迭代对象,在这种情况下,您可以使用扩展运算符。以下示例将每个元素的键转换为键数组:

var keys = [...userRoles.keys()];
console.log(keys);

输出:

[ { name: 'John Doe' },
  { name: 'Lily Bush' },
  { name: 'Peter Drucker' } ]

以下将元素的值转换为数组:

let roles = [...userRoles.values()];
console.log(roles);

输出

[ 'admin', 'editor', 'subscriber' ]

通过 key 删除一个元素

要删除映射中的元素,请使用映射的 delete()方法。

userRoles.delete(john);

删除映射的所有元素

要删除 Map 对象中的所有元素,请使用映射 clear() 方法:

userRoles.clear();

因此,现在映射的大小为零。

console.log(userRoles.size); // 0

弱映射

WeakMapMap 类似,只是 WeakMap 的键必须是对象。这意味着当对某个键(对象)的引用超出范围时,相应的值会自动从内存中释放。

WeakMap 仅具有 Map 对象的子集方法:

  • get(key)
  • set(key, value)
  • has(key)
  • delete(key)

以下是 MapWeekMap 之间的主要区别:

  • WeakMap 的元素无法迭代。
  • 无法一次清除所有元素。
  • 无法获取 WeakMap 的大小。

结论

在本教程中,您学习了如何使用 JavaScript Map 对象及其常用的方法来操作映射中的元素或者键值。