当前位置:  开发笔记 > 编程语言 > 正文

JavaScript中是否有任何哈希码函数?

如何解决《JavaScript中是否有任何哈希码函数?》经验,为你挑选了9个好方法。

基本上,我正在尝试创建一个独特对象的对象,一组.我有一个很好的想法,就是只使用带有对象的JavaScript对象作为属性名称.如,

set[obj] = true;

这很有效.它适用于字符串和数字,但对于其他对象,它们似乎都"散列"到相同的值并访问相同的属性.是否有某种方法可以为对象生成唯一的哈希值?字符串和数字如何做,我可以覆盖相同的行为吗?



1> KimKha..:

如果你想在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(按位运算符)中的实现方式.


@qodeninja说谁?这是我第一次听到这样的说法.你能链接到某些来源吗?哈希值通常使用固定大小的整数运算和位运算来计算,因此获得正或负结果是可以预期的.
@qodeninja和@szeryf:你必须要小心如何使用它.例如,我试图为一个带有20个元素的数组`pickOne`执行`pickOne ["helloo".hashCode()%20]`.我得到了'undefined`,因为哈希码是负数,所以这是一个例子,其中有人(我)暗中假设正哈希码.
挑剔,但......"if(this.length == 0)返回哈希;" 是多余的:)并将个人改变"字符"为"代码".
@qodeninja负数有什么问题?
这会产生-hash,而不是完美
@KimKha`char`是JS中的保留字,可能会导致一些问题.其他一些名字会更好.
@szeryf哈希通常是正面的

2> eyelidlessne..:

JavaScript对象只能使用字符串作为键(其他任何东西都转换为字符串).

或者,您可以维护一个数组,该数组索引相关对象,并使用其索引字符串作为对象的引用.像这样的东西:

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

显然它有点冗长,但是你可以编写一些处理它的方法,然后设置所有方法.

编辑:

您的猜测是事实 - 这是JavaScript中定义的行为 - 特别是发生toString转换意味着您可以在将用作属性名称的对象上定义您自己的toString函数. - olliej

这带来了另一个有趣的观点; 您可以在要散列的对象上定义toString方法,并且可以形成其哈希标识符.


为什么接受答案?这在许多方面都是错误的.
如果每次引用它们时需要对数组进行线性扫描,那么散列对象的重点是什么?
我喜欢这个解决方案,因为它不需要对象中的任何其他属性.但是,如果你想要一个干净的垃圾收集器,它就会出现问题.在您的方法中,它将保存对象,尽管其他引用已被删除.这可能会导致更大的应用程序出现问题.
如果您添加两次相同的对象,这将失败.它会认为它是不同的.

3> Daniel X Moo..:

最简单的方法是为每个对象提供自己独特的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的退出对象的条目.

现在我所有的哈希都非常寒冷.我几天前刚刚发布了一篇关于这个话题的博客文章.


但这忽略了重点.Java有`equals()`和`hashCode()`,因此两个等效对象具有相同的哈希值.使用上面的方法意味着`MyObject`的每个实例都有一个唯一的字符串,这意味着你必须保持对该对象的引用,以便从地图中检索正确的值.拥有密钥是没有意义的,因为它与对象的唯一性无关.对于您用作键的特定类型的对象,需要实现一个有用的`toString()`函数.
@Metalstorm问题不是询问"真正的"哈希码,而是如何在JavaScript中成功使用对象作为集合.
是的,这是使用`toString()`的唯一**正确方法,允许你使用`Object`作为`Set`.我想我误解了你的答案,试图提供一个通用的解决方案,以避免在逐个案例的基础上编写一个`toString()`相当于`equals()`或`hashCode()`.
Dowvoted.这不是一个哈希码是什么,看到我的答案:http://stackoverflow.com/a/14953738/524126和真正实施的hashCode:http://stackoverflow.com/a/15868654/524126

4> theGecko..:

我选择的解决方案类似于Daniel的解决方案,但不是使用对象工厂并覆盖toString,而是在首次通过getHashCode函数请求时向表中显式添加哈希.有点凌乱,但更符合我的需求:)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '';
        }
        return this.hashCode;
    }
}(0));


如果你想这样做,最好通过`Object.defineProperty`设置hashCode,并将`enumerable`设置为`false`,这样你就不会崩溃任何`for ... in`循环.

5> 小智..:

您所描述的内容由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-mapsflag.



6> ijmacd..:

对于我的具体情况,我只关心对象和原始值的对象是否相等.对我有用的解决方案是将对象转换为其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
// }



7> olliej..:

JavaScript规范将索引属性访问定义为对索引名称执行toString转换.例如,

myObject[myProperty] = ...;

是相同的

myObject[myProperty.toString()] = ...;

这在JavaScript中是必要的

myObject["someProperty"]

是相同的

myObject.someProperty

是的,这让我很伤心:-(



8> Metalstorm..:

我刚才把一个小的JavaScript模块放在一起,为字符串,对象,数组等生成哈希码(我只是将它提交给GitHub :))

用法:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159


@Metalstorm"然后你需要重构你的代码"你在开玩笑吗?每个DOM元素父对子对构成一个循环引用.
它对具有数字属性的对象进行散列很糟糕,在很多情况下返回相同的值,即`var hash1 = Hashcode.value({a:1,b:2}); var hash2 = Hashcode.value({a:2,b:1}); console.log(hash1,hash2);`将记录`2867874173``2877874173`

9> Daniel X Moo..:

在ECMAScript 6中,现在可以按照Set您的方式工作:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

它已经在最新的Chrome,FF和IE11中提供.

推荐阅读
手机用户2402852387
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有