散列 JavaScript 对象

Posted

技术标签:

【中文标题】散列 JavaScript 对象【英文标题】:Hashing JavaScript objects 【发布时间】:2014-02-16 00:59:32 【问题描述】:

我有一个接收 JS 对象列表作为参数的函数。我需要将有关这些对象的信息存储在私有变量中以供将来参考。我不想将属性填充到对象本身中,我只想将其保留在字典中。我需要能够在亚线性时间内查找对象的元数据。

为此,我需要一个 hash 函数,这样,对于任意两个对象 o1o2

hash(o1) !== hash(o2) 每当o1 !== o2

这种散列函数的一个完美例子是对象的内存地址,但我认为 JS 不会暴露这一点。有什么办法吗?

【问题讨论】:

你可以直接检查引用相等o1 === o2 在 JS 中,表达式 === 的计算结果为 false。您是否希望 哈希到相同的值? Google Closure 库只是为对象添加了一个独特的属性:docs.closure-library.googlecode.com/git/…。 @masonk 然后自己存储对象并使用===。它不会很快,但我不认为你可以在不接触物体的情况下做得更好。 当 jQuery 试图为.data() 解决这个问题时,它会向源对象添加一个唯一的字符串属性,作为字典中的查找键。然后,如果有人给您源对象,您可以检索查找键,然后在您的字典中查找它以获取并行数据。对象引用本身不能被字符串化为唯一,因此您不能将其用作键。 【参考方案1】:

每个对象引用都是不同的。为什么不将对象推到数组上?遍历数组以查找对象引用可能仍然比在递归庄园中检查每个对象以生成哈希键更好。

function Dictionary() 
    var values = [];

    function contains(x) 
        var i = values.length;

        while(i--) 
            if (values[i] === x) 
                return true;
            
        

        return false;
    

    function count() 
        return values.length;
    

    function get(i) 
        return (i >= 0 && i < values.length) ? values[i] : null;
    

    function set(o) 
        if (contains(o)) 
            throw new Error("Object already exists in the Dictionary");
        
        else 
            return values.push(o) - 1;
        
    

    function forEach(callback, context) 
        for (var i = 0, length = values.length; i < length; i++) 
            if (callback.call(context, values[i], i, values) === false) 
                break;
            
        
    

    return 
        get: get,
        set: set,
        contains: contains,
        forEach: forEach,
        count: count
    ;

并使用它:

var objects = Dictionary();

var key = objects.set();

var o = objects.get(key);

objects.contains(key); // returns true

objects.forEach(function(obj, key, values) 
    // do stuff
, this);

objects.count(); // returns 1

objects.set(o); // throws an error

【讨论】:

【参考方案2】:

要存储有关对象的元数据,您可以使用WeakMap:

WeakMap 是键/值映射,其中键是对象。


请注意,此 API 仍处于试验阶段,因此尚未得到广泛支持(请参阅 support table)。有一个polyfill implementation 使用defineProperty 来设置GUID(详见here)。

【讨论】:

谢谢,这绝对值得考虑向前兼容。【参考方案3】:

javascript 不提供对内存的直接访问(或对文件系统的直接访问)。

您可能只想在分析(哈希)函数中创建属性/变量,然后将它们返回到调用函数的位置以存储/持久化以供以后参考。

【讨论】:

对不起,我不明白你的提议。也许一个代码示例会清楚【参考方案4】:

感谢所有参与回复的人。你们都让我相信,我想做的事情目前在 JavaScript 中是不可能的。

似乎有两种基本的折衷方案可供使用此用例的人选择:

    使用===进行线性搜索

    === 似乎是区分具有不同引用的两个具有相同值的对象的唯一内置方法。 (如果您有两个对象,o1o2,并进行了深入比较并发现它们的值相同,您可能仍然想知道它们是否引用相同。除了 === 您还可以一些奇怪的事情,比如向o1 添加一个属性,看看是否出现在o2)。

    向对象添加属性。

    我不喜欢这种方法,因为我没有充分的理由必须将这些信息暴露给外界。但是,一位同事向我介绍了一个我不知道的功能:Object.defineProperty. 有了这个,我可以减轻我的主要担忧:首先,我的 id 会在对象枚举期间出现,不需要,其次,如果发生命名空间冲突,有人可能会无意中更改我的 ID。

所以,如果有人来这里想要我想要的相同的东西,我会把它放在那里作为记录,我将使用 Object.defineProperty 添加一个唯一的 id。

【讨论】:

以上是关于散列 JavaScript 对象的主要内容,如果未能解决你的问题,请参考以下文章

JavaScrip和Java一样吗?

JavaScrip之BOMday0914

散列 JavaScript 对象

web前端 --- JavaScrip基础

JavaScrip继承图文总结

JavaScript基础介绍