【JavaScript】JS——Map数据类型
- 什么是Map?
- 特性
- Map与Object的比较
- map的创建
- map的属性
- map相关方法
- map的遍历
什么是Map?
存储键值对的对象。
- 能够记住键的原始插入顺序
- 任何值(对象或原始值)都可以作为键或值。
特性
Map中的一个键只能出现一次,新的值会覆盖旧的值。
迭代方式:for…of循环,返回一个 [key,value]
的数组。
键的相等:基于零值相等比较
NaN === NaN
-0 === +0
Map与Object的比较
- Map默认不包含任何键。它只包含显示存入的键值对。
object
有原型
let map1 = new Map()
let obj1 = new Object()
console.log(map1);
console.log(obj1);
-
安全性:
Map
是一种独立的数据结构,不存在对象原型。而在Object
上设置用户提供的键值对可能会允许攻击者覆盖对象的原型,这可能会引发潜在的安全问题:- 原型链污染:攻击者通过提供特定的键值对,污染对象的原型链。例如,攻击者可以通过设置
__proto__
属性来修改对象的原型,从而修改或劫持对象的原型上的方法和属性。 - 函数劫持:如果用户提供的键值对中的值是一个函数,并且该函数被直接赋值给对象的属性,攻击者可能会通过提供恶意的函数来劫持对象的属性。
- 对象重写:如果用户提供的键值对中的键与对象的原型中的属性冲突,攻击者可能通过提供特定的键值对来覆盖对象的原型属性。
- 访问限制绕过
const victim = {}; const attacker = { evilMethod: () => console.log('恶意方法被调用') }; victim.__proto__ = attacker; // 调用原型上的恶意方法 victim.evilMethod(); // 恶意方法被调用
- 原型链污染:攻击者通过提供特定的键值对,污染对象的原型链。例如,攻击者可以通过设置
-
键的类型:
Map
的键可以为任何值(函数、对象或任何原始值),Object
的键必须为String
或Symbol
-
键为函数实例:缓存函数调用结果
const cache = new Map(); function createCacheKey(fn, ...args) { return `${fn.name}(${args.join(',')})`; } function calculateResult(x, y) { const cacheKey = createCacheKey(calculateResult, x, y); if (cache.has(cacheKey)) { console.log('从缓存中获取结果'); return cache.get(cacheKey); } const result = x + y; cache.set(cacheKey, result); return result; } console.log(calculateResult(2, 3)); // 输出:5 console.log(calculateResult(2, 3)); // 输出:从缓存中获取结果,5
-
-
键的顺序:
Map
对象按照插入的顺序迭代条目、键和值。 -
大小:
Map
中的项目数量,使用size
属性获知,Object通常是通过获取Object.keys()
返回的数组长度。 -
迭代:Map 是可迭代对象,
Object
没有实现迭代协议,默认不能通过for ...of
实现迭代 -
性能:涉及频繁添加和删除键值对的场景表现更好
-
序列化或解析:
Map
没有序列化或解析的原生支持;Object
支持使用JSON。stringify()
序列化Object到JSON,使用JSON.parse()
解析JSON为Object
map的创建
- 语法
new Map()
new Map(iterable)
iterable
一个元素是键值对的数组或其他可迭代对象。
const map1 = new Map()
const map2 = new Map([
[1, "a"],
[2, "b"],
[3, "c"],
[4, "c"]
])
console.log(map1,map2);
map的属性
size()
map2.size // 4
map相关方法
get()
get(key)
获取该 map 中的指定元素
console.log(map2.get(1)); // a
set()
set(key, value)
向 Map
对象添加或更新一个指定的键值对
map1.set("a", 1)
map1.set("a", 3)
map1.set("b", 2)
// 链式添加 键值对
map1.set("bar","foo").set(1, "foobar")
console.log(map1);
has()
返回一个布尔值,指示具有指定键的元素是否存在.
delete()
delete(key)
从该 map 中删除指定键的元素。
console.log(map1.delete("a")); // true 删除成功返回true
clear()
移除该 map 中的所有元素.
map1.clear()
console.log(map1); // Map(0) {size: 0}
groupBy()
Map.groupBy(items, callbackFn)
Map对象每个元素都执行提供的回调函数,根据回调函数返回的值进行分组
const inventory = [
{ name: 'Tom', age: 9 },
{ name: 'Bob', age: 5 },
{ name: 'Alice', age: 23 },
{ name: 'Taixi', age: 12 },
];
const result = Map.groupBy(inventory, ({ age }) =>
age < 18 ? "teenager" : "young",
);
console.log(result.get("teenager"));
map的遍历
forEach()
forEach(callbackFn)
按插入顺序对该 map 中的每个键/值对执行一次提供的函数。
const map2 = new Map([
[1, "a"],
[2, "b"],
[3, "c"],
[4, "c"]
])
function logMapElement(value, key, map) {
console.log(`m[${key}]=${value}=${map.get(key)}`);
}
map2.forEach(logMapElement)
entries()
按照插入顺序,返回一个新的可迭代迭代器对象,包含了Map对象中的所有键值对。
const mapIter = map2.entries()
console.log(mapIter.next().value);
console.log(mapIter.next().value);
console.log(mapIter.next().value);
keys() | values()
返回一个迭代器对象,keys()方法返回Map对象中每个元素的键,values()方法返回Map对象中每个元素的值。
const mapIter1 = map2.keys()
console.log(mapIter1.next().value);
console.log(mapIter1.next().value);
console.log(mapIter1.next().value);
const mapIter2 = map2.values()
console.log(mapIter2.next().value);
console.log(mapIter2.next().value);
console.log(mapIter2.next().value);