映射
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Map
对象保存键值对并记住键的原始插入顺序。任何值(对象和 primitive values)都可以用作键或值。
¥The Map
object holds key-value pairs and remembers the original insertion order of the keys.
Any value (both objects and primitive values) may be used as either a key or a value.
Try it
描述
¥Description
Map
对象是键值对的集合。Map
中的一个键只能出现一次;它在 Map
系列中是独一无二的。Map
对象通过键值对进行迭代 - for...of
循环为每次迭代返回 [key, value]
的 2 成员数组。迭代按照插入顺序进行,这对应于 set()
方法首先将每个键值对插入到映射中的顺序(即,当调用 set()
时,映射中不存在具有相同值的键) )。
¥Map
objects are collections of key-value pairs. A key in the Map
may only occur once; it is unique in the Map
's collection. A Map
object is iterated by key-value pairs — a for...of
loop returns a 2-member array of [key, value]
for each iteration. Iteration happens in insertion order, which corresponds to the order in which each key-value pair was first inserted into the map by the set()
method (that is, there wasn't a key with the same value already in the map when set()
was called).
该规范要求映射要实现 "平均而言,提供的访问时间与集合中元素的数量呈次线性关系"。因此,它可以在内部表示为哈希表(具有 O(1) 查找)、搜索树(具有 O(log(N)) 查找)或任何其他数据结构,只要复杂度优于 O (N)。
¥The specification requires maps to be implemented "that, on average, provide access times that are sublinear on the number of elements in the collection". Therefore, it could be represented internally as a hash table (with O(1) lookup), a search tree (with O(log(N)) lookup), or any other data structure, as long as the complexity is better than O(N).
关键平等
¥Key equality
值相等基于 SameValueZero 算法。(以前使用 SameValue,将 0
和 -0
视为不同的。检查 浏览器兼容性。)这意味着 NaN
被认为与 NaN
相同(即使 NaN !== NaN
),并且根据 ===
运算符的语义,所有其他值都被认为是相等的。
¥Value equality is based on the SameValueZero algorithm. (It used to use SameValue, which treated 0
and -0
as different. Check browser compatibility.) This means NaN
is considered the same as NaN
(even though NaN !== NaN
) and all other values are considered equal according to the semantics of the ===
operator.
对象与映射
¥Objects vs. Maps
Object
与 Map
类似 - 两者都允许你将键设置为值、检索这些值、删除键以及检测键中是否存储了某些内容。由于这个原因(并且因为没有内置的替代方案),Object
在历史上一直被用作 Map
。
¥Object
is similar to Map
—both let you set keys to
values, retrieve those values, delete keys, and detect whether something is
stored at a key. For this reason (and because there were no built-in
alternatives), Object
has been used as Map
historically.
然而,在某些情况下,存在一些重要的差异,使得 Map
更可取:
¥However, there are important differences that make Map
preferable in some
cases:
映射 | 对象 | |
---|---|---|
意外按键 | 默认情况下, Map 不包含任何键。它仅包含明确放入其中的内容。 |
注意:可以使用 |
安全 | Map 可以安全地与用户提供的键和值一起使用。 |
在 |
关键类型 | Map 的键可以是任何值(包括函数、对象或任何原语)。 |
Object 的密钥必须是 String 或 Symbol 。 |
关键订单 |
|
虽然普通 该顺序最初仅在 ECMAScript 2015 中为自己的属性定义;ECMAScript 2020 还定义了继承属性的顺序。但请注意,没有单一机制可以迭代对象的所有属性;各种机制各自包含不同的属性子集。( |
尺寸 |
Map 中的项目数可以轻松地从其 size 属性中检索。 |
确定 Object 中的项目数量更加迂回且效率较低。一种常见的方法是通过从 Object.keys() 返回的数组的 length 。 |
迭代 |
Map 是
iterable,因此可以直接迭代。
|
注意:
|
性能 |
在频繁添加和删除键值对的场景中表现更好。 |
未针对频繁添加和删除键值对进行优化。 |
序列化和解析 |
没有对序列化或解析的原生支持。
(但是你可以通过使用 |
使用 原生支持使用 |
设置对象属性
¥Setting object properties
设置对象属性也适用于 Map 对象,但可能会导致相当大的混乱。
¥Setting Object properties works for Map objects as well, and can cause considerable confusion.
因此,这似乎以某种方式起作用:
¥Therefore, this appears to work in a way:
const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
但这种设置属性的方式不会与 Map 数据结构交互。它利用了通用对象的特性。'bla' 的值不存储在 Map 中以供查询。对数据的其他操作失败:
¥But that way of setting a property does not interact with the Map data structure. It uses the feature of the generic object. The value of 'bla' is not stored in the Map for queries. Other operations on the data fail:
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
在 Map 中存储数据的正确用法是通过 set(key, value)
方法。
¥The correct usage for storing data in the Map is through the set(key, value)
method.
const contacts = new Map();
contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });
contacts.has("Jessie"); // true
contacts.get("Hilary"); // undefined
contacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });
contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete("Raymond"); // false
contacts.delete("Jessie"); // true
console.log(contacts.size); // 1
类似映射的浏览器 API
¥Map-like browser APIs
类似浏览器 Map
的对象(或 "类似地图的对象")是 Web API 接口,其行为在很多方面与 Map
类似。
¥Browser Map
-like objects (or "maplike objects") are Web API interfaces that behave in many ways like a Map
.
就像 Map
一样,条目可以按照添加到对象的顺序进行迭代。类似 Map
的对象和 Map
也具有共享相同名称和行为的属性和方法。然而,与 Map
不同的是,它们只允许每个条目的键和值的特定预定义类型。
¥Just like Map
, entries can be iterated in the same order that they were added to the object.
Map
-like objects and Map
also have properties and methods that share the same name and behavior.
However unlike Map
they only allow specific predefined types for the keys and values of each entry.
允许的类型在规范 IDL 定义中设置。例如,RTCStatsReport
是一个类似 Map
的对象,必须使用字符串作为键,使用对象作为值。这是在下面的 IDL 规范中定义的:
¥The allowed types are set in the specification IDL definition.
For example, RTCStatsReport
is a Map
-like object that must use strings for keys and objects for values.
This is defined in the specification IDL below:
interface RTCStatsReport {
readonly maplike<DOMString, object>;
};
类似 Map
的对象要么是只读的,要么是可读写的(请参阅上面 IDL 中的 readonly
关键字)。
¥Map
-like objects are either read-only or read-writable (see the readonly
keyword in the IDL above).
- 类似
Map
的只读对象具有size
属性和方法:entries()
、forEach()
、get()
、has()
、keys()
、values()
和[Symbol.iterator]()
。 - 可写
Map
类对象还具有以下方法:clear()
、delete()
和set()
。
除了对键和值类型的限制之外,方法和属性与 Map
中的等效实体具有相同的行为。
¥The methods and properties have the same behavior as the equivalent entities in Map
, except for the restriction on the types of the keys and values.
以下是类似 Map
的只读浏览器对象的示例:
¥The following are examples of read-only Map
-like browser objects:
构造函数
静态属性
静态方法
实例属性
¥Instance properties
这些属性在 Map.prototype
上定义并由所有 Map
实例共享。
¥These properties are defined on Map.prototype
and shared by all Map
instances.
Map.prototype.constructor
-
创建实例对象的构造函数。对于
Map
实例,初始值为Map
构造函数。 Map.prototype.size
-
返回
Map
对象中键/值对的数量。 Map.prototype[Symbol.toStringTag]
-
[Symbol.toStringTag]
属性的初始值为字符串"Map"
。该属性在Object.prototype.toString()
中使用。
实例方法
¥Instance methods
Map.prototype.clear()
-
从
Map
对象中删除所有键值对。 Map.prototype.delete()
-
如果
Map
对象中的元素存在并已被删除,则返回true
;如果该元素不存在,则返回false
。之后map.has(key)
将返回false
。 Map.prototype.entries()
-
返回一个新的 Iterator 对象,该对象包含
[key, value]
的两个成员数组,其中每个元素按插入顺序排列在Map
对象中。 Map.prototype.forEach()
-
按插入顺序,对
Map
对象中存在的每个键值对调用callbackFn
一次。如果向forEach
提供了thisArg
参数,它将用作每个回调的this
值。 Map.prototype.get()
-
返回与传递的键关联的值,如果没有则返回
undefined
。 Map.prototype.has()
-
返回一个布尔值,指示某个值是否已与
Map
对象中传递的键关联。 Map.prototype.keys()
-
返回一个新的 Iterator 对象,其中包含按插入顺序排列的
Map
对象中每个元素的键。 Map.prototype.set()
-
设置
Map
对象中传递的键的值。返回Map
对象。 Map.prototype.values()
-
返回一个新的 Iterator 对象,其中包含按插入顺序排列的
Map
对象中每个元素的值。 Map.prototype[Symbol.iterator]()
-
返回一个新的 Iterator 对象,该对象包含
[key, value]
的两个成员数组,其中每个元素按插入顺序排列在Map
对象中。
示例
使用映射对象
¥Using the Map object
const myMap = new Map();
const keyString = "a string";
const keyObj = {};
const keyFunc = function () {};
// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
console.log(myMap.size); // 3
// getting the values
console.log(myMap.get(keyString)); // "value associated with 'a string'"
console.log(myMap.get(keyObj)); // "value associated with keyObj"
console.log(myMap.get(keyFunc)); // "value associated with keyFunc"
console.log(myMap.get("a string")); // "value associated with 'a string'", because keyString === 'a string'
console.log(myMap.get({})); // undefined, because keyObj !== {}
console.log(myMap.get(function () {})); // undefined, because keyFunc !== function () {}
使用 NaN 作为 Map 键
¥Using NaN as Map keys
NaN
也可以用作密钥。即使每个 NaN
都不等于自身(NaN !== NaN
为真),以下示例仍然有效,因为 NaN
彼此无法区分:
¥NaN
can also be used as a key. Even though every NaN
is
not equal to itself (NaN !== NaN
is true), the following example works because
NaN
s are indistinguishable from each other:
const myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN);
// "not a number"
const otherNaN = Number("foo");
myMap.get(otherNaN);
// "not a number"
使用 for...of 迭代映射
¥Iterating Map with for...of
可以使用 for...of
循环迭代映射:
¥Maps can be iterated using a for...of
loop:
const myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (const [key, value] of myMap) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
for (const key of myMap.keys()) {
console.log(key);
}
// 0
// 1
for (const value of myMap.values()) {
console.log(value);
}
// zero
// one
for (const [key, value] of myMap.entries()) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
使用 forEach() 迭代映射
与数组对象的关系
¥Relation with Array objects
const kvArray = [
["key1", "value1"],
["key2", "value2"],
];
// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray);
console.log(myMap.get("key1")); // "value1"
// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray
// A succinct way to do the same, using the spread syntax
console.log([...myMap]);
// Or use the keys() or values() iterators, and convert them to an array
console.log(Array.from(myMap.keys())); // ["key1", "key2"]
克隆和合并映射
¥Cloning and merging Maps
就像 Array
一样,Map
也可以被克隆:
¥Just like Array
s, Map
s can be cloned:
const original = new Map([[1, "one"]]);
const clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false (useful for shallow comparison)
注意:请记住,数据本身并未被克隆。
¥Note: Keep in mind that the data itself is not cloned.
可以合并地图,保持键的唯一性:
¥Maps can be merged, maintaining key uniqueness:
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// Merge two maps. The last repeated key wins.
// Spread syntax essentially converts a Map to an Array
const merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
映射也可以与数组合并:
¥Maps can be merged with Arrays, too:
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// Merge maps with an array. The last repeated key wins.
const merged = new Map([...first, ...second, [1, "eins"]]);
console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
规范
Specification |
---|
ECMAScript Language Specification # sec-map-objects |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also