基本上,我正在尝试创建一个独特对象的对象,一组.我有一个很好的想法,就是只使用带有对象的JavaScript对象作为属性名称.如,
set[obj] = true;
这很有效.它适用于字符串和数字,但对于其他对象,它们似乎都"散列"到相同的值并访问相同的属性.是否有某种方法可以为对象生成唯一的哈希值?字符串和数字如何做,我可以覆盖相同的行为吗?
如果你想在JavaScript中使用类似Java的hashCode()函数,那就是你的:
String.prototype.hashCode = function(){ var hash = 0; for (var i = 0; i < this.length; i++) { var character = this.charCodeAt(i); hash = ((hash<<5)-hash)+character; hash = hash & hash; // Convert to 32bit integer } return hash; }
这是Java(按位运算符)中的实现方式.
JavaScript对象只能使用字符串作为键(其他任何东西都转换为字符串).
或者,您可以维护一个数组,该数组索引相关对象,并使用其索引字符串作为对象的引用.像这样的东西:
var ObjectReference = []; ObjectReference.push(obj); set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;
显然它有点冗长,但是你可以编写一些处理它的方法,然后设置所有方法.
编辑:
您的猜测是事实 - 这是JavaScript中定义的行为 - 特别是发生toString转换意味着您可以在将用作属性名称的对象上定义您自己的toString函数. - olliej
这带来了另一个有趣的观点; 您可以在要散列的对象上定义toString方法,并且可以形成其哈希标识符.
最简单的方法是为每个对象提供自己独特的toString
方法:
(function() { var id = 0; /*global MyObject */ MyObject = function() { this.objectId = '<#MyObject:' + (id++) + '>'; this.toString= function() { return this.objectId; }; }; })();
我有同样的问题,这解决它完美的我以最小的大惊小怪,并且是一个更容易的是重新实现一些脂肪的Java风格Hashtable
并加入equals()
和hashCode()
你的对象类.只要确保你没有将一个字符串'<#MyObject:12>粘贴到你的哈希中,否则它将清除你带有该id的退出对象的条目.
现在我所有的哈希都非常寒冷.我几天前刚刚发布了一篇关于这个话题的博客文章.
我选择的解决方案类似于Daniel的解决方案,但不是使用对象工厂并覆盖toString,而是在首次通过getHashCode函数请求时向表中显式添加哈希.有点凌乱,但更符合我的需求:)
Function.prototype.getHashCode = (function(id) { return function() { if (!this.hashCode) { this.hashCode = ''; } return this.hashCode; } }(0));
您所描述的内容由Harmony WeakMaps涵盖,它是ECMAScript 6规范(下一版JavaScript)的一部分.即:一个集合,其中键可以是任何东西(包括未定义的)并且是不可枚举的.
这意味着除非您直接引用链接到它的键(任何对象!),否则无法获取对值的引用.这对于一系列与效率和垃圾收集相关的引擎实现原因很重要,但它也非常酷,因为它允许新的语义,如可撤销访问权限和传递数据而不暴露数据发送者.
来自MDN:
var wm1 = new WeakMap(), wm2 = new WeakMap(); var o1 = {}, o2 = function(){}, o3 = window; wm1.set(o1, 37); wm1.set(o2, "azerty"); wm2.set(o1, o2); // A value can be anything, including an object or a function. wm2.set(o3, undefined); wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps! wm1.get(o2); // "azerty" wm2.get(o2); // Undefined, because there is no value for o2 on wm2. wm2.get(o3); // Undefined, because that is the set value. wm1.has(o2); // True wm2.has(o2); // False wm2.has(o3); // True (even if the value itself is 'undefined'). wm1.has(o1); // True wm1.delete(o1); wm1.has(o1); // False
目前的Firefox,Chrome和Edge都提供WeakMaps.它们也在Node v7中支持,在v6中也支持--harmony-weak-maps
flag.
对于我的具体情况,我只关心对象和原始值的对象是否相等.对我有用的解决方案是将对象转换为其JSON表示并将其用作哈希.有一些限制,例如密钥定义的顺序可能不一致; 但就像我说它对我有用,因为这些对象都是在一个地方生成的.
var hashtable = {}; var myObject = {a:0,b:1,c:2}; var hash = JSON.stringify(myObject); // '{"a":0,"b":1,"c":2}' hashtable[hash] = myObject; // { // '{"a":0,"b":1,"c":2}': myObject // }
JavaScript规范将索引属性访问定义为对索引名称执行toString转换.例如,
myObject[myProperty] = ...;
是相同的
myObject[myProperty.toString()] = ...;
这在JavaScript中是必要的
myObject["someProperty"]
是相同的
myObject.someProperty
是的,这让我很伤心:-(
我刚才把一个小的JavaScript模块放在一起,为字符串,对象,数组等生成哈希码(我只是将它提交给GitHub :))
用法:
Hashcode.value("stackoverflow") // -2559914341 Hashcode.value({ 'site' : "stackoverflow" }) // -3579752159
在ECMAScript 6中,现在可以按照Set
您的方式工作:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
它已经在最新的Chrome,FF和IE11中提供.