基本上,我试图创建一个由独特对象组成的对象,一个集合。我有一个绝妙的主意,就是将 JavaScript 对象与属性名称的对象一起使用。如,
set[obj] = true;
这在一定程度上是有效的。它适用于字符串和数字,但对于其他对象,它们似乎都“散列”到相同的值并访问相同的属性。有什么方法可以为对象生成唯一的哈希值吗?字符串和数字如何做到这一点,我可以覆盖相同的行为吗?
基本上,我试图创建一个由独特对象组成的对象,一个集合。我有一个绝妙的主意,就是将 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(按位运算符)中的实现方式。
请注意 hashCode 可能为正也可能为负,这很正常,请参阅HashCode 给出负值。因此,您可以考虑Math.abs()
与此功能一起使用。
JavaScript 对象只能使用字符串作为键(其他任何东西都转换为字符串)。
或者,您可以维护一个数组来索引相关对象,并使用其索引字符串作为对对象的引用。像这样的东西:
var ObjectReference = [];
ObjectReference.push(obj);
set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;
显然它有点冗长,但是您可以编写一些方法来处理它,并且可以随意获取和设置所有内容。
编辑:
您的猜测是事实——这是 JavaScript 中定义的行为——特别是发生 toString 转换意味着您可以在将用作属性名称的对象上定义自己的 toString 函数。- 奥利耶
这带来了另一个有趣的观点;你可以在你想要散列的对象上定义一个 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 的退出对象的条目。
现在我所有的哈希都完全凉了。几天前我也刚刚发布了一篇关于这个确切主题的博客文章。
您描述的内容包含在 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
WeakMaps 在当前的 Firefox、Chrome 和 Edge 中可用。它们在 Node v7 和带有--harmony-weak-maps
标志的v6 中也受支持。
我选择的解决方案类似于 Daniel 的解决方案,但我没有使用对象工厂并覆盖 toString,而是在首次通过 getHashCode 函数请求对象时显式地将散列添加到对象中。有点乱,但更适合我的需要:)
Function.prototype.getHashCode = (function(id) {
return function() {
if (!this.hashCode) {
this.hashCode = '<hash|#' + (id++) + '>';
}
return this.hashCode;
}
}(0));