发布于 2026-01-05 3 阅读
0

选择 JavaScript Map 而不是 Object 来存储键值对的 5 个理由(附示例)

选择 JavaScript Map 而不是 Object 来存储键值对的 5 个理由(附示例)

18岁时,我开始了我的“职业生涯”,做IT支持人员。20
岁时,我成为了一名空乘人员,每月飞行80小时。22
岁时,我拿到了商用飞机飞行员执照。29
岁时,我是一名木匠,而如今32岁的我,是一名软件开发人员。

如果说我有什么擅长的,那就是跟上时代的步伐。因为如果你跟不上,就会被时代抛弃。我深知,使用自己熟记于心的东西比尝试“新事物”要舒服得多。

但不适感能让你成长,无论作为一个人还是一个开发者。

让我们一头扎进去,看看这些“新事物”Map今天能给我们带来什么启示。

Map 对象是什么?

以下是权威来源(MDN)的定义:

Map 对象存储键值对,并记住键的原始插入顺序。任何值(包括对象和基本类型值)都可以用作键或值。

简单来说,Map 是 JavaScript 的原生哈希或字典数据结构。

语法:Map 与 Object

这里有一张方便的速查表,很好地展示了它们的语法差异,这是Andrej在 Twitter 上发布的。

图片描述

他还录制了性能测试视频,如果你感兴趣的话。

原因一:您不会意外覆盖默认密钥。

默认情况下, Map
对象不包含任何键。它是一个空白的画布,只包含你放入其中的内容。

不多不少,恰到好处。

图片描述

对象
默认具有其原型,因此它包含默认键,这些默认键可能会与您自己的键冲突。

null可以通过在创建新对象时将原型传递来绕过此问题:Object.create(null)

看看区别:

  • 新对象

图片描述

  • null带有原型的新对象

图片描述

原因二:它接受任何类型的键

Map
接受任何类型的键。这包括函数、对象和所有基本类型(字符串、数字、布尔值、符号、undefined、null 和 bigint)。

let obj = { 'a': 'a' };
let func = () => 'hey';

//you can also initialize multiple values at once using array syntax
let map = new Map([[123, true], [true, 123], [obj, 'object'], [func, 'function']])

map.keys() // 123, true, Object, () => 'hey'
map.get(obj) // 'object'
map.get(func) // 'function'
map.get({ 'a': 'a' }) // undefined 
//Object and Functions are stored by reference, so { 'a':'a' } and obj are different objects)
Enter fullscreen mode Exit fullscreen mode

对象
对象的键必须是字符串或符号。

let obj1 = { 'a': 'a' };
let func = () => 'hey';

let obj = { 123: true, true: 123, obj1: 'object', func: 'function' };
Object.keys(obj) 
// ['123', 'true', 'obj1', 'func'] converts all keys to strings

obj[func] //undefined
obj['func'] // 'function'
Enter fullscreen mode Exit fullscreen mode

原因三:地图是可迭代的

Map
本身是可迭代的。这意味着你可以使用循环遍历for of它们.forEach()

const map = new Map();
map.set(0, 'zero').set(1, 'one'); //you can chain .set()

for (const [key, value] of map) {
  console.log(`key: ${key}, value: ${value}`);
}
// key: 0, value: zero
// key: 1, value: one

//if you just want the 'values' or just the 'keys'
for (const key of map.keys()) { // or map.values()
  console.log(key);
}
// 0
// 1

map.forEach((value, key) => console.log(`key: ${key}, value: ${value}`));
// key: 0, value: zero
// key: 1, value: one
Enter fullscreen mode Exit fullscreen mode

对象
本身是不可迭代的,即使你可以使用for in`and`来遍历它们。Object.Entries()

let obj = { 0: 'zero', 1: 'one' }

for(let key in obj){
    console.log(`key: ${key}, value: ${obj[key]}`)
}
// key: 0, value: zero
// key: 1, value: one

Object.entries(obj).forEach((item) => console.log(`key: ${item[0]}, value: ${item[1]}`))
// key: 0, value: zero
// key: 1, value: one

Enter fullscreen mode Exit fullscreen mode

原因四:映射可以与数组合并,也可以转换为数组。

Map
和 Array 完全兼容,因此可以轻松地在两者之间进行转换。

以下是如何将 a 转换Map为 an 的方法Array

let map = new Map([ [1, 'one'], [2, 'two'] ]);
Array.from(map) //[ [1, 'one'], [2, 'two'] ] exactly the same array you initially passed in

//or you can use the spread operator
const newArr = [...map];
Enter fullscreen mode Exit fullscreen mode

进入Array一个Map

let arr = [ [1, 'one'], [2, 'two'] ];
new Map(arr); //{ 1 => 'one', 2 => 'two' }
Enter fullscreen mode Exit fullscreen mode

以下是如何合并aMap和 an 的方法Array

let map = new Map([ [1, 'one'], [2, 'two'] ]);
let arr = [3, 'three']

let combinedMap = new Map(...map, arr); 
// { 1 => 'one', 2 => 'two', 3 => 'three' }

let combinedArr = [...map, arr];
// [ [1, 'one'], [2, 'two'], [3, 'three'] ]
Enter fullscreen mode Exit fullscreen mode

对象
协调成Object一个Array

let obj = { 1: 'one', 2: 'two'};
Array.from(obj) // [] doesn't work

//you'd have to do
Array.from(Object.entries(obj))
//[ ['1', 'one'],['2', 'two'] ]

//or
[...Object.entries(obj)]
//[ ['1', 'one'],['2', 'two'] ]
Enter fullscreen mode Exit fullscreen mode

原因五:您可以轻松查看尺寸

Map
有一个内置size属性可以返回其大小。

let map = new Map([1, 'one'], [true, 'true']);
map.size // 2
Enter fullscreen mode Exit fullscreen mode

要检查对象
的大小,您需要结合Object.keys()使用.length

let obj = { 1: 'one', true: 'true' };
Object.keys(obj).length // 2
Enter fullscreen mode Exit fullscreen mode

缺点?没有用于序列化和解析的本地方法。

Map
本身不支持与 JSON 进行序列化或解析。

文档建议通过使用replacer可以传递给JSON.stringify(obj, replacer)reviver传递给的参数来实现自己的功能。JSON.parse(string, reviver)

您可以在这里找到建议的实现方案。

对象您可以使用相应的方法
将对象原生序列化和解析为 JSON,反之亦然。JSON.stringify()JSON.parse()

2 个可以Object用以下方式替换的例子Map

#1计算电子商务购物车的总价和商品数量

这是《JavaScript 完全指南》中 .reduce() 函数的示例之一。

给定以下数组

const shoppintCart = [
  { price: 10, amount: 1 },
  { price: 15, amount: 3 },
  { price: 20, amount: 2 },
]
Enter fullscreen mode Exit fullscreen mode

我们想要返回一个Object类似这样的结果:{ totalItems: 6, totalPrice: 45 }

这是原始代码

shoppintCart.reduce(
  (accumulator, currentItem) => {
    return {
      totalItems: accumulator.totalItems + currentItem.amount,
      totalPrice:
        accumulator.totalPrice + currentItem.amount * currentItem.price,
    }
  },
  { totalItems: 0, totalPrice: 0 } //initial value object
)
// { totalItems: 6, totalPrice: 45 }
Enter fullscreen mode Exit fullscreen mode

这是使用以下版本的Map

shoppintCart.reduce(
  (accumulator, currentItem) => {
      accumulator.set('totalItems', accumulator.get('totalItems') + currentItem.amount);
      accumulator.set('totalPrice', accumulator.get('totalPrice') + currentItem.price);
      return accumulator;
  },
  new Map([['totalItems', 0], ['totalPrice', 0]])
)
// { 'totalItems' => 6, 'totalPrice' => 45 }
Enter fullscreen mode Exit fullscreen mode

#2从数组中删除重复对象的另一种方法

这是我刚开始学习 JavaScript 时,在自己开发的图书架应用中使用的一段代码。

我在谷歌上搜索如何从数组中删除重复对象,找到了下面我分享的示例。

这是一个包含重复对象的数组

const books = [
  { id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' },
  { id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' },
  { id: 2, title: 'The Alchemist', author: 'Paulo Coelho' },
]
Enter fullscreen mode Exit fullscreen mode

这里有一种奇特的删除重复项的方法:


const uniqueObjsArr = [
   ...new Map(books.map(book => [book.id, book])).values()
];
Enter fullscreen mode Exit fullscreen mode

上面这短短一句话信息量有点大。
我们把它拆分成几个部分,以便更容易理解。


// 1. map the array into an array of arrays with `id` and `book`

const arrayOfArrays = books.map(book => [ book.id, book ])
// arrayOfArrays:
/*
[ 
   [ 1, {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' } ],
   [ 1, {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie' } ],
   [ 2, { title: 'Alchemist', author: 'Paulo Coelho' } ]
]
*/

// 2. The duplicate is automatically removed as keys have to be unique

const mapOfUniqueObjects = new Map(arrayOfArrays)
// mapOfUniqueObjects: 
/*
{
   1 => {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie'},
   2 => { title: 'Alchemist', author: 'Paulo Coelho' }
}
*/

// 3. Convert the values back into an array.

const finalResult = [...mapOfUniqueObjects.values()];
// finalResult:
/*
[
   {id: 1, title: 'How To Win Friends And Influence People', author: 'Dale Carnegie'},
   {id: 2, title: 'The Alchemist', author: 'Paulo Coelho'}
]
*/
Enter fullscreen mode Exit fullscreen mode

结论

如果需要存储键值对(哈希或字典),请使用Map

如果你只使用基于字符串的键,并且需要最高的读取性能,那么对象可能是更好的选择。

除此之外,你想用什么都行,因为说到底,这只是一个普通网友在网上写的一篇博客文章而已,哈哈。

以下是我们报道的内容:

  • Map 对象是什么?
  • 语法:Map 与 Object
  • 原因一:您不会意外覆盖默认密钥。
  • 原因二:它接受任何类型的键
  • 原因三:地图是可迭代的
  • 原因四:映射可以与数组合并,也可以转换为数组。
  • 原因五:您可以轻松查看尺寸
  • 缺点?没有用于序列化和解析的本地方法。
  • 2 个可以Object用以下方式替换的例子Map

感谢阅读!

如果您喜欢这篇文章:

*请在下方留言(打个招呼也行!)
*在推特上关注我@theguspear

回头见,

格斯。

文章来源:https://dev.to/gustavupp/5-reasons-to-choose-javascript-maps-over-objects-for-storing-key-value-pairswith-examples-39dd