164

基本的に、私はユニークなオブジェクトのオブジェクト、セットを作成しようとしています。プロパティ名のオブジェクトでJavaScriptオブジェクトを使用するという素晴らしいアイデアがありました。そのような、

set[obj] = true;

これは、ある程度までは機能します。文字列と数値でうまく機能しますが、他のオブジェクトでは、それらはすべて同じ値に「ハッシュ」され、同じプロパティにアクセスするように見えます。オブジェクトの一意のハッシュ値を生成する方法はありますか?文字列と数値はどのように機能しますか?同じ動作をオーバーライドできますか?

4

20 に答える 20

69

Java の JavaScript のような 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()したがって、この機能と一緒に使用することを検討できます。

于 2011-11-10T08:01:44.717 に答える
36

JavaScriptオブジェクトは、文字列のみをキーとして使用できます(それ以外は文字列に変換されます)。

または、問題のオブジェクトにインデックスを付ける配列を維持し、そのインデックス文字列をオブジェクトへの参照として使用することもできます。このようなもの:

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

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

明らかにそれは少し冗長ですが、それを処理し、すべての意地悪なものを取得して設定するいくつかのメソッドを書くことができます。

編集:

あなたの推測は事実です-これはJavaScriptで定義された動作です-具体的にはtoString変換が発生します。つまり、プロパティ名として使用されるオブジェクトに独自のtoString関数を定義できます。--olliej

これは別の興味深い点をもたらします。ハッシュするオブジェクトにtoStringメソッドを定義でき、それによってハッシュ識別子を形成できます。

于 2008-10-12T00:42:56.663 に答える
23

あなたが説明したことは、 ECMAScript 6仕様 (JavaScript の次のバージョン) の一部であるHarmony WeakMapsでカバーされています。つまり、キーが何でも (未定義を含む)、列挙不可能なセットです。

これは、値にリンクするキー (任意のオブジェクト!) への直接参照がない限り、値への参照を取得できないことを意味します。これは、効率とガベージ コレクションに関連する多くのエンジン実装上の理由から重要ですが、取り消し可能なアクセス許可や、データ送信者を公開せずにデータを渡すなどの新しいセマンティクスを可能にするという点でも非常にクールです。

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 でもサポートされています。

于 2011-11-10T09:31:39.277 に答える
18

私が選んだソリューションは Daniel のものと似ていますが、オブジェクト ファクトリを使用して toString をオーバーライドするのではなく、getHashCode 関数を介して最初に要求されたときにオブジェクトにハッシュを明示的に追加します。少し面倒ですが、私のニーズには適しています:)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));
于 2011-04-26T13:10:36.263 に答える
16

私の特定の状況では、キーとプリミティブ値に関する限り、オブジェクトの同等性のみを気にします。私にとってうまくいった解決策は、オブジェクトを JSON 表現に変換し、それをハッシュとして使用することでした。キー定義の順序が矛盾する可能性があるなどの制限があります。しかし、私が言ったように、これらのオブジェクトはすべて 1 か所で生成されていたので、うまくいきました。

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
// }
于 2014-03-11T16:30:17.257 に答える
9

ECMAScript 6 では、希望どおりにSet機能する があります: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

最新の Chrome、FF、IE11 ではすでに利用可能です。

于 2015-01-13T19:48:40.933 に答える
8

JavaScript仕様では、インデックス付きプロパティアクセスを、インデックス名に対してtoString変換を実行するものとして定義しています。例えば、

myObject[myProperty] = ...;

と同じです

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

これはJavaScriptのように必要です

myObject["someProperty"]

と同じです

myObject.someProperty

そして、はい、それは私も悲しくなります:-(

于 2008-10-12T08:02:24.500 に答える
1

私のソリューションでは、グローバルObjectオブジェクトに静的関数を導入しています。

(function() {
    var lastStorageId = 0;

    this.Object.hash = function(object) {
        var hash = object.__id;

        if (!hash)
             hash = object.__id = lastStorageId++;

        return '#' + hash;
    };
}());

これは JavaScript の他のオブジェクト操作関数と組み合わせるとより便利だと思います。

于 2013-02-19T09:14:07.103 に答える
0

設定された動作が本当に必要な場合 (私は Java の知識に頼っています)、JavaScript で解決策を見つけるのは難しいでしょう。ほとんどの開発者は、各オブジェクトを表す一意のキーを推奨しますが、これは set とは異なり、それぞれが一意のキーを持つ 2 つの同一のオブジェクトを取得できます。Java API は、キーではなくハッシュ コード値を比較することによって重複値をチェックする作業を行います。JavaScript にはオブジェクトのハッシュ コード値表現がないため、同じことを行うことはほとんど不可能になります。Prototype JS ライブラリでさえ、この欠点を認めています。

「ハッシュは、一意のキーを値 (必ずしも一意ではない) にバインドする連想配列と考えることができます...」

http://www.prototypejs.org/api/hash

于 2008-10-12T01:49:29.260 に答える
0

ルックアップ オブジェクトに一意の値を持たせたい場合は、次のようにすることができます。

ルックアップ オブジェクトの作成

var lookup = {};

ハッシュコード関数の設定

function getHashCode(obj) {
    var hashCode = '';
    if (typeof obj !== 'object')
        return hashCode + obj;
    for (var prop in obj) // No hasOwnProperty needed
        hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
    return hashCode;
}

物体

var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;

配列

var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;

その他のタイプ

var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;

最終結果

{ 1337: true, 01132337: true, StackOverflow: true }

getHashCodeオブジェクトまたは配列が空の場合は値を返さないことに注意してください

getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'

これは @ijmacd ソリューションに似ていますが、依存関係getHashCodeがないだけです。JSON

于 2016-10-22T01:38:39.530 に答える
0

まぶたのない人の答えに加えて、任意のオブジェクトに対して再現可能な一意の ID を返す関数を次に示します。

var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
    // HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
    if (uniqueIdList.indexOf(element) < 0) {
        uniqueIdList.push(element);
    }
    return uniqueIdList.indexOf(element);
}

ご覧のとおり、ルックアップに非常に非効率なリストを使用していますが、今のところこれが最善の方法です。

于 2012-07-11T20:29:32.717 に答える
0

オブジェクトをキーとして使用したい場合は、すでにここで述べたように、toString メソッドを上書きする必要があります。使用されたハッシュ関数はすべて問題ありませんが、同等のオブジェクトではなく、同じオブジェクトに対してのみ機能します。

オブジェクトからハッシュを作成する小さなライブラリを作成しました。これは、この目的で簡単に使用できます。オブジェクトの順序が異なっていても、ハッシュは同じになります。内部的には、ハッシュにさまざまなタイプを使用できます (djb2、md5、sha1、sha256、sha512、ripemd160)。

ドキュメントの小さな例を次に示します。

var hash = require('es-hash');

// Save data in an object with an object as a key
Object.prototype.toString = function () {
    return '[object Object #'+hash(this)+']';
}

var foo = {};

foo[{bar: 'foo'}] = 'foo';

/*
 * Output:
 *  foo
 *  undefined
 */
console.log(foo[{bar: 'foo'}]);
console.log(foo[{}]);

このパッケージは、ブラウザーと Node-Js のどちらでも使用できます。

リポジトリ: https://bitbucket.org/tehrengruber/es-js-hash

于 2013-01-22T22:35:59.553 に答える