ES6中的地图与对象,何时使用?


83

参考:MDN地图

当键直到运行时才是未知的,并且所有键都是相同的类型并且所有值都是相同的类型时,请在对象上使用映射。

当存在对单个元素进行操作的逻辑时,请使用对象。

题:

在对象上使用地图的适用示例是什么?特别是,“什么时候直到运行时才知道密钥?”

var myMap = new Map();

var keyObj = {},
    keyFunc = function () { return 'hey'},
    keyString = "a string";

// 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.get(keyFunc));

是的,我注意到了。当我将函数设置为值时。@JonathanLonowski您能想到我什么时候应该这样做:((对用例的思考很难。–
Matthew Harwood

7
您可以在要使用Object关联某些数据的DOM元素的地方使用它。不用说元素的ID作为对象中的键,而是可以将元素本身用作Map中的键,这样就不必关心元素是否具有ID(或对象引用以外的任何其他唯一标识符) ) 或不。
RobG

1
@RobG只是一点点补充:在这种情况下,它WeakMap可能也会有所帮助。
zerkms 2015年

1
我认为这建议将对象用作/用于记录,并使用Maps进行其他所有类型的映射。与记录我的意思是用一组固定的领域,如具有的字段的用户对象的数据结构nameid例如。
菲利克斯·克林

1
当我阅读该MDN页面时,用例的项目符号列表比您引用的段落要有用得多。当然与您的标题中提出的问题有关。
CodingIntrigue

Answers:


51

在对象上使用地图的适用示例是什么?

我认为您已经给出了一个很好的例子:Map使用对象(包括Function对象)作为键时,至少需要使用s。

特别是,“什么时候直到运行时才知道密钥?”

只要在编译时不知道它们。简而言之,Map当您需要键值集合时,应始终使用a 。当您从集合中动态添加和删除值时,尤其是当您事先不知道这些值(例如,它们是从数据库中读取,用户输入等)时,便是需要集合的一个很好的指示。

相反,当您知道对象在编写代码时具有哪些属性以及多少属性时(形状是静态的),应该使用对象。正如@Felix所说的:需要记录时。一个很好的指示是,当字段具有不同的类型,以及您永远不需要使用方括号表示法(或期望其中包含有限的属性名称)时。


1
或从另一个角度来看:每当需要在数据级别(例如for..of)而不是程序级别(例如for..in)遍历对象的属性时,请使用Map。有关此术语的更多信息,请参见本回复

我要补充的评论也是事实,任何时候,你不知道你的关键将是什么样的类型,你不希望字符串作为关键数据类型,然后使用地图stackoverflow.com/questions/32600157/...
胭脂红Tambascia

26

我认为使用ES2015的Map唯一两个原因是使用普通对象:

什么时候财产顺序不重要?

  • 如果您只有一个值,并且应将某些函数与它显式关联(例如Promise-是将来值的代理-和then/ catch
  • 如果您具有类似结构/记录的数据结构,并且在“编译时”知道一组静态属性(通常结构/记录是不可迭代的)

在所有其他情况下,您可能会考虑使用Map,因为它会保留属性顺序并将程序(分配给Map对象的所有属性)与数据级别(Map本身的所有条目)分开。

有什么缺点Map

  • 您失去了简洁的对象文字语法
  • 您需要JSON.stringyfy的自定义替换器
  • 您将失去解构能力,无论如何这对于静态数据结构来说更有用

这条线让我非常担忧:“它可能比​​纯类似哈希图的对象要慢”,因为性能提高,我想到了用地图替换所有对象。但是你说它慢一些……
mesqueeb

1
你是对的。Map可能更快,因为它纯粹基于散列,而Object复杂一些。谢谢!

11

当键直到运行时才是未知的,并且所有键都是同一类型并且所有值都是同一类型时,请在对象上使用映射。

我不知道为什么有人会写出如此明显的错误。我不得不说,这些天人们在MDN上发现了越来越多的错误和/或可疑内容。

那句话中没有什么是对的。使用映射的主要原因是当您需要对象值键。值应该是相同类型的想法是荒谬的,尽管它们当然可以。同样的荒谬的想法是,在密钥未知之前,不应使用对象,直到运行时。


1
我看不出这个想法有什么荒谬的?当您需要集合时,通常会严格地对它们进行类型化(当然,可能会有例外)。另外,我认为不再使用对象进行收集(如果Map可用)是个好建议。
Bergi

为此,从逻辑上讲,严格意义上的集合通常不同于说严格意义上的东西应该是集合。

1
是的,我认为这有点奇怪,但是这个主意很好。我猜他们以为“键直到运行时才是未知的”已经收集了。有更好的措辞想法吗?
Bergi 2015年

1
同意 MDN有非常好的文档,但是他们应该坚持对API文档进行文档编制,而不要尝试给出编程建议。
AlexG

5

Map和之间的区别之一Object是:

Map可以使用复杂的数据类型作为其键。像这样:

const fn = function() {}
const m = new Map([[document.body, 'stackoverflow'], [fn, 'redis']]);

m.get(document.body) // 'stackoverflow'
m.get(fn) //'redis'

注意:对于复杂的数据类型,如果要获取值,则必须传递与键相同的引用。

Object,它仅接受简单数据类型(numberstring)作为其键。

const a = {};
a[document.body] = 'stackoverflow';

console.log(a) //{[object HTMLBodyElement]: "stackoverflow"}

2

这个问题是重复的 但是直到关闭,这是我从那儿得到答案

除了其他答案之外,我发现与对象相比,使用Map更麻烦,更冗长。

obj[key] += x
// vs.
map.set(map.get(key) + x)

这很重要,因为较短的代码读取速度更快,表达更直接,并且更好地掌握在程序员的脑海中

另一方面:因为set()返回映射而不是值,所以不可能链接分配。

foo = obj[key] = x;  // Does what you expect
foo = map.set(key, x)  // foo !== x; foo === map

调试地图也更加痛苦。在下面,您实际上看不到地图中的键。您必须编写代码才能做到这一点。

祝您评估Map Iterator好运

可以通过任何IDE评估对象:

WebStorm评估对象


6
这根本没有回答“在对象上使用Maps的适用示例是什么? ”的问题
Bergi

6
请不要交叉发布您的答案。不,问题不是重复的。
贝尔吉'17

1

Objects与s相似Map,两者都允许您将键设置为值,检索这些值,删除键以及检测是否在键上存储了某些内容。因此(由于没有内置替代方法),Objects在Map历史上一直被用作s。但是,Map在某些情况下,最好使用一个重要的区别:

  • an的键ObjectStrings和Symbols,而它们的键可以是a的任何值Map,包括函数,对象和任何基元。
  • 中的键Map是有序的,而添加到对象的键则无序。因此,在对其进行迭代时,Map对象按插入顺序返回键。
  • 您可以通过属性Map轻松获得尺寸size,而Object必须手动确定。
  • AMap是可迭代的,因此可以直接进行迭代,而对a进行迭代则Object需要以某种方式获取其密钥并对其进行迭代。
  • 一个Object已具雏形,所以有在,如果你不小心,可能与你的钥匙碰撞地图默认密钥。从ES5开始,可以使用来绕过它map = Object.create(null),但这很少完成。
  • Map在涉及频繁添加和删除密钥对的情况下,A可能会表现更好。

MDN

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.