Map
功能和c++的unordered_map功能差不多
Map 对象是键值对的集合。Map 中的一个键只能出现一次;它在 Map 的集合中是独一无二的。Map 对象按键值对迭代——一个 for...of 循环在每次迭代后会返回一个形式为 [key, value] 的数组。迭代按_插入顺序_进行,即键值对按 set() 方法首次插入到集合中的顺序(也就是说,当调用 set() 时,map 中没有具有相同值的键)进行迭代。
规范要求 map 实现“平均访问时间与集合中的元素数量呈次线性关系”。因此,它可以在内部表示为哈希表(使用 O(1) 查找)、搜索树(使用 O(log(N)) 查找)或任何其他数据结构,只要复杂度小于 O(N)。
构造方法
map()
语法
new Map()
new Map(iterable)
备注: Map() 只能用 new 构造。尝试不使用 new 调用它会抛出 TypeError。
参数
iterable 可选
一个元素是键值对的数组或其他可迭代对象。(例如,包含两个元素的数组,如 [[ 1, 'one' ],[ 2, 'two' ]]。)每个键值对都被添加到新的 Map 中。
示例
创建一个新的 Map
const myMap = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
键的相等
键的比较基于零值相等算法。(它曾经使用同值相等,将 0 和 -0 视为不同。检查浏览器兼容性。)这意味着 NaN 是与 NaN 相等的(虽然 NaN !== NaN),剩下所有其他的值是根据 === 运算符的结果判断是否相等。
Object与map的区别 查看MDN吧
设置对象属性
设置对象属性同样适用于 Map 对象,但容易造成困扰。
即,以下的代码能够正常运行(==但不推荐==):
const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
但这种设置属性的方式不会改变 Map 的数据结构。它使用的是通用对象的特性。'bla' 的值未被存储在 Map 中,无法被查询到。其他的对这一数据的操作也会==失败==:
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
正确的存储数据到 Map 中的方式是使用 set(key, value) 方法。
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
实例属性(函数)
- Map.size() 返回长度
const map1 = new Map();
map1.set('a', 'alpha');
map1.set('b', 'beta');
map1.set('g', 'gamma');
console.log(map1.size);
// Expected output: 3
- Map.clear() 清空Map
const map1 = new Map();
map1.set('bar', 'baz');
map1.set(1, 'foo');
console.log(map1.size);
// Expected output: 2
map1.clear();
console.log(map1.size);
// Expected output: 0
- Map.delete(key) 删除键值对
传入参数为key
移除
Map对象中指定的键值对,如果键值对存在并成功被移除,返回true,否则返回false。调用delete后再调用map.has(key)将返回false。
const map1 = new Map();
map1.set('bar', 'foo');
console.log(map1.delete('bar'));
// Expected result: true
// True indicates successful removal
console.log(map1.has('bar'));
// Expected result: false
-
Map.entries() 创建迭代器 无参数 返回一个新的迭代器对象,其包含
Map对象中所有键值对[key, value]二元数组,以插入顺序排列。实际应用:
- 当你需要同时访问 Map 的键和值时,
entries()方法非常有用。 - 它常用于遍历 Map 对象,特别是在
for...of循环中。 注意事项: entries()方法返回的是一个迭代器,而不是一个数组。- 如果你需要一个真正的数组,可以使用
Array.from()或展开运算符...来转换。 替代方法: Map对象本身就是可迭代的,所以你也可以直接对 Map 使用for...of循环,得到的结果与使用entries()相同。
- 当你需要同时访问 Map 的键和值时,
const myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");
const mapIter = myMap.entries();
console.log(mapIter.next().value); // ["0", "foo"]
console.log(mapIter.next().value); // [1, "bar"]
console.log(mapIter.next().value); // [Object, "baz"]
// 创建一个 Map
const fruits = new Map();
// 添加一些键值对
fruits.set('apple', 5);
fruits.set('banana', 3);
fruits.set('orange', 2);
// 使用 entries() 方法
const entriesIterator = fruits.entries();
// 遍历迭代器
for (let entry of entriesIterator) {
console.log(entry);
}
/*
['apple', 5]
['banana', 3]
['orange', 2]
*/
- Map.forEach() 遍历
以插入顺序为
Map对象中的每个键值对调用一次callbackFn。如果为forEach提供了thisArg参数,则它将作为每一次 callback 的this值。
function logMapElements(value, key, map) {
console.log(`m[${key}] = ${value}`);
}
new Map([
['foo', 3],
['bar', {}],
['baz', undefined],
]).forEach(logMapElements);
// Expected output: "m[foo] = 3"
// Expected output: "m[bar] = [object Object]"
// Expected output: "m[baz] = undefined"
- Map.get() 获取
返回与指定的键
key关联的值,若不存在关联的值,则返回undefined。
const map1 = new Map();
map1.set('bar', 'foo');
console.log(map1.get('bar'));
// Expected output: "foo"
console.log(map1.get('baz'));
// Expected output: undefined
- Map.has() 查找是否存在
返回一个布尔值,用来表明
Map对象中是否存在与指定的键key关联的值。
const map1 = new Map();
map1.set('bar', 'foo');
console.log(map1.has('bar'));
// Expected output: true
console.log(map1.has('baz'));
// Expected output: false
- Map.keys() 返回一个只包含键的迭代器
返回一个新的迭代器对象,其包含
Map对象中所有元素的键,以插入顺序排列。
// 创建一个新的 Map
const fruits = new Map();
// 添加一些键值对
fruits.set('apple', 'red');
fruits.set('banana', 'yellow');
fruits.set('grape', 'purple');
// 使用 keys() 方法获取键的迭代器
const keysIterator = fruits.keys();
console.log('Keys iterator:', keysIterator);
// 遍历键
for (const key of keysIterator) {
console.log(key);
}
// 将迭代器转换为数组
const keysArray = Array.from(fruits.keys());
console.log('Keys array:', keysArray);
/*
`Keys iterator: [Map Iterator] { 'apple', 'banana', 'grape' }`
`apple banana grape Keys array: [ 'apple', 'banana', 'grape' ]`
*/
注意与entries() 的区别
-
返回的数据:
keys()只返回键。entries()返回键值对。
-
使用场景:
- 如果你只需要处理 Map 的键,使用
keys()更加简洁和高效。 - 如果你需要同时处理键和值,
entries()更适合。
- 如果你只需要处理 Map 的键,使用
-
遍历结果:
keys()遍历结果是单个值。entries()遍历结果是一个包含两个元素的数组。
-
转换为数组:
Array.from(map.keys())会得到一个只包含键的数组。Array.from(map.entries())会得到一个包含键值对数组的数组。
-
Map.set() 插入新元素 在
Map对象中设置与指定的键key关联的值,并返回Map对象。
const map1 = new Map();
map1.set('bar', 'foo');
console.log(map1.get('bar'));
// Expected output: "foo"
console.log(map1.get('baz'));
// Expected output: undefined
// 链式添加元素
myMap.set("bar", "foo").set(1, "foobar").set(2, "baz");
- Map.values() 返回一个只包含value的迭代器
返回一个新的迭代对象,其中包含
Map对象中所有的值,并以插入Map对象的顺序排列。 和keys相对
const myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");
const mapIter = myMap.values();
console.log(mapIter.next().value); // "foo"
console.log(mapIter.next().value); // "bar"
console.log(mapIter.next().value); // "baz"
Map[Symbol.iterator]()创建数组 返回一个新的迭代器对象,其包含Map对象中所有元素[key, value]二元数组,以插入顺序排列。
const map1 = new Map();
map1.set('0', 'foo');
map1.set(1, 'bar');
const iterator1 = map1[Symbol.iterator]();
for (const item of iterator1) {
console.log(item);
}
// Expected output: Array ["0", "foo"]
// Expected output: Array [1, "bar"]
示例
-
使用Map对象
-
将NaN作为Map的键
-
使用for...of迭代Map
-
使用forEach() 迭代Map
-
Map与数组对象的关系
-
复制或合并Maps
Map能像数组一样被复制:
const original = new Map([[1, "one"]]);
const clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false. 浅比较 不为同一个对象的引用
**备注:**请记住,_数据本身_未被克隆。
Map 对象间可以进行合并,但是会保持键的唯一性。
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的。
// 展开语法本质上是将 Map 对象转换成数组。
const merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
Map 对象也能与数组合并:
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// Map 对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。
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