该表示法是:
var hash = {};
hash[X]
实际上不哈希对象X
;它实际上只是转换X
为字符串(通过.toString()
它是一个对象,还是其他各种原始类型的内置转换),然后在“
hash
”中查找该字符串,而不对其进行哈希处理。也不会检查对象是否相等-如果两个不同的对象具有相同的字符串转换,则它们将彼此覆盖。
鉴于此-在JavaScript中是否有任何有效的hashmap实现?(例如,第二个Google结果javascripthashmap
产生的实现对任何操作都是O(n)。其他各种结果都忽略了这样的事实,即具有等效字符串表示形式的不同对象会相互覆盖。
为什么不自己手动对对象进行哈希处理,然后将结果字符串用作常规JavaScript词典的键?毕竟,您处于最佳位置,知道什么使您的对象独特。我就是做这个的。
例:
var key = function(obj){
// some unique object-dependent key
return obj.totallyUniqueEmployeeIdKey; // just an example
};
var dict = {};
dict[key(obj1)] = obj1;
dict[key(obj2)] = obj2;
这样,您可以控制由JavaScript完成的索引编制,而不会大量增加内存分配和溢出处理。
当然,如果您真正想要“工业级解决方案”,则可以构建一个由键函数参数化的类,并带有容器的所有必需API,但是…我们使用JavaScript,并试图做到简单轻巧,因此此功能解决方案既简单又快速。
密钥功能可以很简单,例如,选择对象的正确属性(例如,一个密钥或一组密钥,这些属性已经是唯一的),密钥的组合(这些密钥一起是唯一的),或者像使用某些加密哈希一样复杂在DojoXEncoding或DojoXUUID中。尽管后一种解决方案可能会产生唯一键,但我个人还是不惜一切代价避免使用它们,特别是如果我知道是什么使我的对象变得唯一时。
2014年更新: 早在2008年就回答了这个简单的解决方案,但仍需要更多说明。让我以问答形式澄清这个想法。
您的解决方案没有真正的哈希。 它在哪里???
JavaScript是一种高级语言。它的基本原语(Object)包括用于保留属性的哈希表。为了提高效率,通常用低级语言编写此哈希表。通过使用带有字符串键的简单对象,我们无需任何努力即可使用高效实现的哈希表。
您怎么知道他们使用哈希?
保持键可寻址的对象集合的三种主要方法:
显然,JavaScript对象使用某种形式的哈希表来处理一般情况。
浏览器供应商是否真的使用哈希表???
真。
Chrome / node.js / V8: JSObject。寻找 NameDictionary和 NameDictionaryShape与相关细节objects.cc 和对象- inl.h。
Firefox/Gecko: JSObject, NativeObject和 PlainObject与相关细节 jsobj.cpp和 VM / NativeObject.cpp。
他们会处理碰撞吗?
是。看上面。如果发现不相等的字符串发生冲突,请立即向供应商提交错误报告。
那你的主意是什么?
如果要对对象进行哈希处理,请查找使其唯一的原因并将其用作键。不要尝试计算真实的哈希或模拟哈希表-基础JavaScript对象已经有效地处理了它。
将此键与JavaScript一起使用Object
可利用其内置的哈希表,同时避免使用默认属性发生可能的冲突。
入门示例:
我使用了您的建议,并使用用户名缓存了所有对象。 但是,一个聪明人被称为“ toString”,这是一个内置属性!我现在应该怎么做?
显然,如果生成的键很可能仅由拉丁字符组成,那么您应该对此做一些事情。例如,在开头或结尾添加您喜欢的任何非拉丁Unicode字符,以使用默认属性“
通常,这里是我们必须发挥创造力的地方,然后选择具有给定限制(唯一性,具有默认属性的潜在冲突)的最简单的键。
注意:根据定义,唯一键不会发生冲突,而潜在的哈希冲突将由底层进行处理Object
。
您为什么不喜欢工业解决方案?
恕我直言,最好的代码是根本没有代码:它没有错误,不需要维护,易于理解并且可以立即执行。我看到的所有“
JavaScript中的哈希表”都是100行以上的代码,并且涉及多个对象。与进行比较dict[key] = value
。
还有一点:使用JavaScript和完全相同的原始对象来实现已经实现的东西,甚至有可能击败以低级语言编写的原始对象的性能吗?
我仍然想散列没有任何键的对象!
我们很幸运:ECMAScript 6(计划于2015年中期发布,在此之后花上一到两年的时间才能普及)定义了地图和集合。
根据定义判断,他们可以将对象的地址用作键,这使对象无需人工键即可立即与众不同。OTOH,两个不同但相同的对象,将被映射为不同的对象。
来自MDN的比较细分:
对象与Maps相似,两者都允许您将键设置为值,检索这些值,删除键以及检测是否在键处存储了某些内容。因此(由于没有内置的替代方法),对象在历史上一直被用作地图。但是,在某些情况下,使用地图有一些重要的区别:
- 对象的键是字符串和符号,而它们的键可以是Map的任何值,包括函数,对象和任何基元。
- Map中的键是有序的,而添加到对象中的键则没有顺序。因此,在对其进行迭代时,Map对象将按插入顺序返回键。
- 您可以使用size属性轻松获得Map的大小,而Object中的属性数量则必须手动确定。
- Map是可迭代的,因此可以直接进行迭代,而对Object进行迭代需要以某种方式获取其键并对其进行迭代。
- 对象具有原型,因此如果不小心,地图中的默认键可能会与您的键冲突。从ES5开始,可以通过使用map =
Object.create(null)绕过此方法,但这很少完成。- 在涉及频繁添加和删除密钥对的情况下,Map的性能可能更好。
问题内容: 我正在从xml配置转移到注释。我想转换一个会话范围的bean是 可以通过注释完成此操作吗?如果没有,我该怎么做才能使该声明继续工作? 问题答案: 在spring上下文xml中,执行以下操作: 请注意,尽管如此,你将需要为该包中的所有类编写接口。
问题内容: 我正在尝试从Swift的iTunesU中的“开发适用于iPhone和iPad的ios7应用程序”中复制斯坦福Matchismo游戏。 在第3讲幻灯片的第77页上,它显示了使用,这不是Swift上的选项。Swift文档示例显示了一个具有数组的示例,但是我不知道如何使Interface Builder将多个插座连接到同一个/ Array。 有人知道如何做到这一点吗? 我知道我可以创建1
问题内容: 我正在开发Java程序,我确实需要能够以一定的频率和持续时间播放声音,类似于c#方法System.Beep,我知道如何在C#中使用它,但是我找不到用Java做到这一点的一种方法。是否有等效的方法或另一种方法? 问题答案: 我认为没有办法在便携式2 Java 中用“哔”声播放音乐1。您将需要使用我认为的API …除非找到可以为您简化事情的第三方库。 如果您想走这条路,那么此页面可能会给您
问题内容: 我有一些使用Jersey <2.0的经验。现在,我正在尝试构建一个战争应用程序以提供JSON Webservice API。 我现在花了大量时间尝试配置Moxy,而且接缝比添加的要复杂得多 回到Jersey <2.0中的web.xml。 是否有可能只是说“请添加json支持”? 目前,我在服务器上没有任何日志条目的情况下,收到了很多内部服务器错误错误,只是觉得“我必须做完全错误的事情,
问题内容: 据我所知,Java没有C#之类的东西。是否有其他Java库提供类似功能?( 反射反射 )有什么区别? 问题答案: 除了达林的出色答案(+1)外,ASM也值得一试。
问题内容: 是否有斯威夫特的本地等效于? 假设我有两个包含键和值的数组,并想将它们放入字典中。在Objective-C中,我会这样做: 当然,我可以遍历两个数组的计数器,使用a 并逐步添加内容。但这似乎不是一个好的解决方案。同时使用和可能是更好的迭代方式。但是,这种方法意味着拥有可变的字典,而不是不可变的字典。 问题答案: 从 Swift 4开始, 您可以直接从键/值对序列创建字典: 这假定所有键