JavaScript中的Map 与 Object

本文探讨了JavaScript中Map和Object的区别,Map提供了安全存储键/值对的方式,避免了原型污染,支持对象键,且保持插入顺序。Map的方法如keys(), values(), entries()返回迭代器,有助于遍历和复制。Map在某些场景下比JSON更优,尤其是需要考虑键的顺序和类型时。" 111622150,10293940,使用GROMACS分析VASP动力学结果:VASP2GRO工具,"['VASP', 'GROMACS', '模拟分析', '后处理工具', '动力学']

在JavaScript中,Map 是存储键/值对的对象。Map 类似于一般 JavaScript 对象 ,但对象与 Map 之间一些关键的差异使 Map 很有用。

Map 与 Object

如果你要创建一个存储一些键/值路径的 JavaScript 对象,可以定义一个普通 JavaScript 对象(plain-old JavaScript object),其简称为“ POJO”,如下所示。

const obj = {
  name: 'Jean-Luc Picard',
  age: 59,
  rank: 'Captain'
};

obj.name; // 'Jean-Luc Picard'

你还可以定义一个包含如下所示的键和值的映射。

const map = new Map([
    // 你可以通过二维数组定义 Map。 首先
  // 每个嵌套数组的元素是键,第二个是值
  ['name', 'Jean-Luc Picard'],
  ['age', 59],
  ['rank', 'Captain']
]);

// 要获得与 Map 中给定的“键”关联的值,你需要
// 调用 map.get(key)`。 使用 map.key 将不起作用。
map.get('name'); // 'Jean-Luc Picard'
专门建立的学习Q-q-u-n: 731771211,分享学习方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到前端项目实战教程,学习工具,全栈开发学习路线以及规划)

假设你想获得 Picard 船长的 age。对于一个对象,你可以用 obj.age。对于 map,你要用 map.get(‘age’)。对于与内置 JavaScript 功能没有冲突的属性来说这很好用,但是如果你想获取对象的 constructor 属性会怎样呢?在这种情况下,只定义了 obj.constructor,但未定义 map.get(‘constructor’)。

obj.constructor; // [Function: Object]
map.get('constructor'); // undefined

映射没有继承的任何概念:映射没有任何继承的键。这使 map 成为存储原始数据的理想选择,而不必担心数据与现有方法和属性发生冲突。例如,map 不受原型污染这个安全漏洞的影响,用户数据的简单复制可能会使恶意用户覆盖类方法。

另一个关键差异是,映射允许你存储对象键,而不仅仅是字符串。但是当你把日期或数字等对象存储为键时,可能会引起一些混乱。

const map = new Map([]);

const n1 = new Number(5);
const n2 = new Number(5);

map.set(n1, 'One');
map.set(n2, 'Two');

// n1 和 n2 是对象,因此 n1!== n2。 
// 这意味着 map 具有分别用于 n1 和 n2 的键。
map.get(n1); // 'One'
map.get(n2); // 'Two'
map.get(5); // undefined

//如果要对一个对象执行此操作,则 n2 会覆盖 n1
const obj = {};
obj[n1] = 'One';
obj[n2] = 'Two';

obj[n1]; // 'Two'
obj[5]; // 'Two'

Map 还具有 size 属性,该属性返回 map 中键/值对的数量。为了获得一个对象中键的数量,你必须要调用 Object.keys(obj).length。

map.size; // 3

另一个区别是,这保证了键在 map 中的顺序。换句话说,如果你调用 map.keys(),你将总是按照将键添加到 map 的顺序获取键。在 Picard 船长的示例中,map.keys() 将始终按该顺序返回 name, age 和 rank 。 这也能够保证符合ES6的浏览器的对象键顺序。例如在与 ES6 兼容的 JavaScript 运行时中,Object.keys(obj) 将始终返回 [‘name’, ‘age’, ‘rank’]。但是在较早的运行时(例如 Internet Explorer 等)中,Object.keys(obj) 可能会以不同的顺序返回键。

Map#keys(), Map#values(), Map#entries()

map 具有3种内置的迭代方法:keys(),values())和entries()。与Object.keys()不同,Map#keys() 函数返回一个 iterator 而不是数组。这意味着迭代 map 键的最简单方法是使用 for/of 循环。

const map = new Map([
  ['name', 'Jean-Luc Picard'],
  ['age', 59],
  ['rank', 'Captain']
]);

const iterator = map.keys();
console.log(iterator); // MapIterator { 'name', 'age', 'rank' }

// `map.keys()` returns an iterator, not an array, so you can't
// access the values using `[]`
iterator[0]; // undefined

// The `for/of` loop can loop through iterators
for (const key of map.keys()) {
  key; // 'name', 'age', 'rank'
}
专门建立的学习Q-q-u-n: 731771211,分享学习方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到前端项目实战教程,学习工具,全栈开发学习路线以及规划)

有时将迭代器转换为数组很方便,因此你可以用 filter() 和 map() 。将迭代器转换成数组的最简单方法是使用内置的Array.from() 函数。

const arr = Array.from(map.keys());

arr.length; // 3
arr[0]; // 'name'
arr[1]; // 'age'
arr[2]; // 'rank'

Map#entries() 函数还返回一个迭代器。迭代器遍历 map 的值:

for (const v of map.values()) {
  v; // 'Jean-Luc Picard', 59, 'Captain'
}

最后, Map#entries() 返回一个迭代器,该迭代器以与 Map 构造函数类似的格式遍历 map 的键/值对。 Map#entries()函数是 Map 类的等效项,它等效于 `Object.entries。

for (const [key, value] of map.entries()) {
  key; // 'name', 'age', 'rank'
  value; // 'Jean-Luc Picard', 59, 'Captain'
}

Map#entries() 函数使复制 map 变得很容易。克隆 map 就像将 Map.entries() 转换成数组一样简单:

// `clone` is now a separate map that contains the same keys/values
// as `map`.
const clone = new Map(Array.from(map.entries));

扩展

尽管 JavaScript 开发人员通常用对象来存储数据,但是 map 具有一些优点:没有原型污染或 JSON 数据覆盖类方法的风险。如果要在不设置 symbol 的情况下将数据与对象相关联,映射还允许你存储对象键,这会很有用。Map 在开源 JavaScript 中仍然很少见,我唯一见过的重要用例子是 Mongoose’s map type 。但是 map 值得去取代 JSON ,因为它避免了原型污染的风险。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值