JavaScriptにはなんらかのハッシュコード関数がありますか?


150

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

set[obj] = true;

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


32
すべてのオブジェクトが同じ値に「ハッシュ」される理由は、toStringメソッドをオーバーライドしていないためです。キーは文字列である必要があるため、有効なキーを取得するためにtoStringメソッドが自動的に呼び出され、すべてのオブジェクトが同じデフォルトの文字列「[object Object]」に変換されます。
12

4
JSON.stringify(obj)またはobj.toSource()、問題とターゲットプラットフォームによっては動作する場合があります。
AnnanFay 2013

4
@Annan JSON.stringify(obj)は、文字通り(オブジェクト全体)を文字列に変換します。したがって、基本的にはオブジェクトをそれ自体にコピーするだけです。これは無意味で、スペースの無駄であり、最適ではありません。
Metalstorm 14

1
@Metalstorm True、これが問題の内容に依存する理由です。私がグーグルを介してこの質問を見つけたとき、私の最終的な解決策はオブジェクトのtoSource()を呼び出すことでした。別の方法は、ソースで従来のハッシュを使用することです。
AnnanFay 14

@ Annan、toSourceChrome では機能しない
Pacerier

回答:


35

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

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

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

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

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

編集:

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

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


別のオプションは、ハッシュとして各オブジェクトにランダムな値を与えることです-おそらく乱数+総ティック-そして、配列からオブジェクトを追加/削除する関数のセットを持っています。
Sugendran 08年

4
同じオブジェクトを2回追加すると失敗します。違うと思います。
ダニエルXムーア

「これは、同じオブジェクトを2回追加すると失敗します。異なると考えられます。」いい視点ね。解決策は、ObjectReferenceの配列をサブクラス化して、重複チェックをpush()にフックすることです。現在、このソリューションを編集する時間はありませんが、後で覚えることを願っています。
まぶたがない2009年

8
オブジェクトに追加のプロパティが必要ないため、このソリューションが気に入っています。ただし、クリーンなガベージコレクタを使用しようとすると、問題が発生します。あなたのアプローチでは、他の参照はすでに削除されていますが、オブジェクトを保存します。これは、より大きなアプリケーションで問題を引き起こす可能性があります。
ジョニー

35
オブジェクトを参照するたびに配列の線形スキャンが必要な場合、オブジェクトをハッシュする意味は何ですか?
Bordaigorl 2014年

57

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()この関数と一緒に使用することを検討できます。


5
これにより、完全ではなく-hashが作成されます
qodeninja '14

2
@KimKha charはJSの予約語であり、問​​題が発生する可能性があります。他の名前が良いでしょう。
szeryf 2013

16
@qodeninjaは誰を言っていますか?私がそのような主張を聞いたのは初めてです。いくつかのソースにリンクできますか?ハッシュは通常、固定サイズの整数演算とビット演算を使用して計算されるため、正または負の結果を得ることが期待されます。
szeryf 2013

7
うるさいですが... "if(this.length == 0)return hash;" 冗長です:)そして、個人的に「文字」を「コード」に変更します。
メタルストーム2013

10
@qodeninjaおよび@szeryf:使い方に注意する必要があります。たとえば、20要素のpickOne["helloo".hashCode() % 20]配列を作成しようとしましたpickOneundefinedハッシュコードが負であるために得たので、これは誰か(私)が暗黙的に正のハッシュコードを想定した例です。
Jim Pivarski、2014

31

これを行う最も簡単な方法は、オブジェクトごとに独自の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を持つ既存のオブジェクトのエントリが消去されます。

今私のすべてのハッシュは完全に寒いです。私はまた、この正確なトピックについて数日前にブログエントリを投稿しました。


28
しかし、これは全体の要点を逃しています。Javaはequals()hashCode()2つの同等のオブジェクトが同じハッシュ値を持つようにします。上記の方法を使用すると、のすべてのインスタンスにMyObject一意の文字列が含まれます。つまり、マップから正しい値を取得するには、そのオブジェクトへの参照を保持する必要があります。オブジェクトの一意性とは何の関係もないので、キーを持つことは意味がありません。toString()キーとして使用している特定のタイプのオブジェクトに対して、便利な関数を実装する必要があります。
sethro 2014年

@sethroを使用toStringしてオブジェクトを実装し、等価関係に直接マッピングして、2つのオブジェクトが「等しい」と見なされる場合に同じ文字列を作成するようにすることができます。
Daniel X Moore

3
右、それがあるのみ使用する正しい方法toString()あなたが使用できるようにするObjectとしてSet。私はあなたの答えを、ケースバイケースで、またはケースバイケースでtoString()同等のものを書くことを避けるための一般的な解決策を提供しようとしていると誤解したと思います。equals()hashCode()
sethro 2014年

3
ダウ投票。:これはハッシュコードが何であるかではない、と私の答えを参照stackoverflow.com/a/14953738/524126とhashCodeの真の実装を:stackoverflow.com/a/15868654/524126
Metalstorm

5
@Metalstorm問題は、「真の」ハッシュコードについてではなく、JavaScriptでオブジェクトをセットとして正常に使用する方法です。
Daniel X Moore 14

20

あなたが説明したことは、ECMAScript 6仕様の一部であるHarmony WeakMaps(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

WeakMapは、現在のFirefox、Chrome、およびEdgeで使用できます。これらは、ノードv7と--harmony-weak-mapsフラグ付きのv6でもサポートされています。


1
これらとはどう違いMapますか?
smac89 2017

@ smac89 WeakMapには制限があります。1)キーとしてオブジェクトのみを受け取ります。2)サイズプロパティはありません。3)イテレータまたはforEachメソッドはありません。4)明確なメソッドはありません。キーはオブジェクトです。オブジェクトがメモリから削除されると、このオブジェクトに接続されているWeakMapのデータも削除されます。これは、オブジェクトが存在している間だけ存在するはずの情報を保持したい場合に非常に役立ちます。したがって、WeakMapにはメソッドのみがあります。書き込みと取得のために設定、削除、読み取りのために持つ
Ekaterina Tokareva

これは正確には正しく動作しません... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedsetコマンドで最初に参照したのと同じ変数がある場合にのみ機能します。EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Sancarn

1
@Sancarn同じ変数である必要はありませんが、同じオブジェクトを指す必要があります。最初の例では、2つの異なるオブジェクトがあり、それらは同じに見えますが、アドレスが異なります。
Svish

1
@Svishの良いスポット!私は今それを知っていますが、当時はそうでなかったかもしれません:)
Sancarn

19

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

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));

7
この方法を使用したい場合は、setを使用してhashCode via Object.definePropertyenumerable設定する方がはるかに良いためfalsefor .. inループがクラッシュすることはありません。
Sebastian Nowak 14

14

私の特定の状況では、キーとプリミティブ値が関係する限り、オブジェクトの同等性のみを気にします。私にとってうまくいった解決策は、オブジェクトをその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
// }

10

私は一緒に入れ、小さなJavaScriptのモジュール(私はちょうどそれを約束などの文字列、オブジェクト、配列、のための農産物ハッシュコードを前にしながら、AをGitHubの :))

使用法:

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

javascriptのGCは循環参照にも影響しませんか?
クレイトンラベンダ2013

@Ryan Long循環参照がある場合は、コードをリファクタリングする必要があります;)
Metalstorm

11
@Metalstorm「コードをリファクタリングする必要があります」冗談ですか?すべてのDOM要素の親と子のペアは循環参照を構成します。
Chris Middleton

8
数値的なプロパティを持つオブジェクトのハッシュ処理は貧弱で、多くの場合同じ値が返されvar hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);ます。つまり、ログに記録されます2867874173 2867874173
JulienBérubéMar

9

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

myObject[myProperty] = ...;

と同じです

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

これはJavaScriptと同様に必要です

myObject["someProperty"]

と同じです

myObject.someProperty

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


9

ECMAScript 6には、httpsSet//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Setのように機能するaがあります。

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


1
これが2016年のトップアンサーになるはずです。Babelを使用している場合は、ES6仕様に従ってSetを使用でき、ES5出力で自動的にポリフィルされます。babeljs.io/docs/learn-es2015/#map-set-weak-map-weak-set
atroberts20 16

5

リファレンス:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Es6シンボルを使用して、一意のキーを作成し、オブジェクトにアクセスできます。Symbol()から返されるすべてのシンボル値は一意です。シンボル値は、オブジェクトプロパティの識別子として使用できます。これがデータ型の唯一の目的です。

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

2
シンボルを再生成する方法が実際にはないことを除いて、x = Symbol( 'a'); let y = Symbol( 'a'); console.log(x === y); // falseを返すしたがって、Symbolはハッシュのように機能しません。
Richard Collette、

3

これは、一意の整数を返す簡単な解決策です。

function hashcode(obj) {
    var hc = 0;
    var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
    var len = chars.length;
    for (var i = 0; i < len; i++) {
        // Bump 7 to larger prime number to increase uniqueness
        hc += (chars.charCodeAt(i) * 7);
    }
    return hc;
}

2
これの複雑さは、hashCode()の背後にある全体の考えを損なう
tuxSlayer '27 / 09/27

これが不必要に複雑であるとは思いません。でも気になったのは、なぜ置換フェーズなのか?そうでなければ、除外はcharCodeAtでうまく戻りますね?
Greg Pettit

hashcode({a:1, b:2}) === hashcode({a:2, b:1})と他の多くの紛争のためにあまりにも悪い。
maaartinus

3

タイトルに基づいて、jsで強力なハッシュを生成できます。これを使用して、オブジェクト、パラメーターの配列、文字列などから一意のハッシュを生成できます。

後でインデックスを付けるために、これは起こり得るあらゆるマッチングエラーを回避する一方で、paramsからインデックスを取得することを可能にします(オブジェクトの検索/ループを回避します):

async function H(m) {
  const msgUint8 = new TextEncoder().encode(m)                       
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)          
  const hashArray = Array.from(new Uint8Array(hashBuffer))                    
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  console.log(hashHex)
}

/* Examples ----------------------- */
H("An obscure ....")
H(JSON.stringify( {"hello" : "world"} ))
H(JSON.stringify( [54,51,54,47] ))

私のブラウザでの上記の出力は、あなたにとっても等しいはずです(それは本当にですか?):

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string


1

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

(function() {
    var lastStorageId = 0;

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

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

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

これは、JavaScriptの他のオブジェクト操作関数の方が便利だと思います。


1
同じ内部値を持つオブジェクトは異なるハッシュにハッシュされますが、これはハッシュ(コード)が行うことではありません。
Metalstorm 14

JavaScriptでは(そして私は他のほとんどすべての言語でもそうだと思います)、同じ内部値で作成された2つのオブジェクトは、異なるデータオブジェクトです。jsfiddle.net/h4G9f
ジョニー

4
はい、しかしそれはハッシュコードの目的ではありません、ハッシュコードはオブジェクトの状態の等価性をチェックするために使用されます。ハッシュのように、同じ入力が(変数値)に入り、同じハッシュが出ます。あなたが探しているのはUUIDです(これはあなたの関数が提供するものです)。
Metalstorm 14

1
あなたが正しい。その質問を誤解している。本当に悪いことに、受け入れられた答えも良い解決策を提供しません。
ジョニー

あなたの機能も同様に、次のようにする傾向があります:jsfiddle.net/xVSsd同じ結果、より短く(LoC +文字)、おそらく非常にわずかに速い:)
Metalstorm

1

私は他の答えよりも少し深く行きたいと思います。

JSのハッシュサポートが優れていても、すべてを魔法のように完全にハッシュすることはできません。多くの場合、独自のハッシュ関数を定義する必要があります。たとえば、Javaは優れたハッシュサポートを備えていますが、それでも、考えていくつかの作業を行う必要があります。

1つの問題は、ハッシュ/ハッシュコードという用語にあります...暗号ハッシュと非暗号ハッシュがあります。もう1つの問題は、ハッシュが有用な理由とその仕組みを理解する必要があることです。

JavaScriptまたはJavaでのハッシュについて話すとき、ほとんどの場合、非暗号化ハッシュについて話します。通常、ハッシュマップ/ハッシュテーブルのハッシュについてです(NodeJSを使用してサーバー側で行うことができる認証またはパスワードを扱っている場合を除く)。 ..)。

それはあなたが持っているデータとあなたが達成したいものに依存します。

データには、いくつかの自然な「単純な」一意性があります。

  • 整数のハッシュは...整数です。それはユニークなので、ラッキーです!
  • 文字列のハッシュ...文字列に依存します。文字列が一意の識別子を表す場合は、ハッシュと見なすことができます(ハッシュは必要ありません)。
  • 間接的にほとんど一意の整数であるものは、最も単純なケースです
  • これは尊重します:オブジェクトが等しい場合、ハッシュコードは等しい

データには、いくつかの自然な「複合」一意性があります。

  • たとえば、人物オブジェクトの場合、firstname、lastname、birthdateなどを使用してハッシュを計算できます。Javaの仕組みを確認してください:文字列に適したハッシュ関数、または安価でユースケースに十分にユニークな他のID情報を使用してください。

あなたはあなたのデータがどうなるか分かりません:

  • 幸運...文字列にシリアル化してJavaスタイルでハッシュすることはできますが、文字列が大きい場合はコストがかかる可能性があり、衝突を回避するだけでなく、整数(自己)のハッシュも言えません。

未知のデータに対する魔法のように効率的なハッシュ手法はありません。場合によっては、非常に簡単な場合もあれば、よく考える必要がある場合もあります。そのため、JavaScript / ECMAScriptがサポートを追加しても、この問題に対する魔法の言語による解決策はありません。

実際には、2つのものが必要です。十分な一意性、十分な速度

それに加えて、「オブジェクトが等しい場合はハッシュコードが等しい」というのは素晴らしいことです。


0

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

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

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


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);
}

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


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-Jのどちらでも使用できます。

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


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依存関係はありません。


循環参照に問題がある
はず

@tuxSlayerお知らせいただきありがとうございます。このコードは必要に応じて簡単に拡張できますが、アイデアが多少明確であることを願っています:)
A1rPun

これにより、ラージオブジェクトの非常に長いキーが生成され、メモリとパフォーマンスにかなりの
Gershom

0

まぶたなしとキムカの答えを組み合わせました。

以下は、angularjsサービスで、数値、文字列、オブジェクトをサポートしています。

exports.Hash = () => {
  let hashFunc;
  function stringHash(string, noType) {
    let hashString = string;
    if (!noType) {
      hashString = `string${string}`;
    }
    var hash = 0;
    for (var i = 0; i < hashString.length; i++) {
        var character = hashString.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function objectHash(obj, exclude) {
    if (exclude.indexOf(obj) > -1) {
      return undefined;
    }
    let hash = '';
    const keys = Object.keys(obj).sort();
    for (let index = 0; index < keys.length; index += 1) {
      const key = keys[index];
      const keyHash = hashFunc(key);
      const attrHash = hashFunc(obj[key], exclude);
      exclude.push(obj[key]);
      hash += stringHash(`object${keyHash}${attrHash}`, true);
    }
    return stringHash(hash, true);
  }

  function Hash(unkType, exclude) {
    let ex = exclude;
    if (ex === undefined) {
      ex = [];
    }
    if (!isNaN(unkType) && typeof unkType !== 'string') {
      return unkType;
    }
    switch (typeof unkType) {
      case 'object':
        return objectHash(unkType, ex);
      default:
        return stringHash(String(unkType));
    }
  }

  hashFunc = Hash;

  return Hash;
};

使用例:

Hash('hello world'), Hash('hello world') == Hash('hello world')
Hash({hello: 'hello world'}), Hash({hello: 'hello world'}) == Hash({hello: 'hello world'})
Hash({hello: 'hello world', goodbye: 'adios amigos'}), Hash({hello: 'hello world', goodbye: 'adios amigos'}) == Hash({goodbye: 'adios amigos', hello: 'hello world'})
Hash(['hello world']), Hash(['hello world']) == Hash(['hello world'])
Hash(1), Hash(1) == Hash(1)
Hash('1'), Hash('1') == Hash('1')

出力

432700947 true
-411117486 true
1725787021 true
-1585332251 true
1 true
-1881759168 true

説明

ご覧のとおり、サービスの中心はKimKhaによって作成されたハッシュ関数です。オブジェクトの構造が最終的なハッシュ値にも影響を与えるように、文字列に型を追加しました。配列|オブジェクトの衝突を防ぐために、キーがハッシュされます。

まぶたのないオブジェクトの比較は、自己参照オブジェクトによる無限再帰を防ぐために使用されます。

使用法

このサービスを作成したのは、オブジェクトでアクセスされるエラーサービスを使用できるようにするためです。そのため、1つのサービスで特定のオブジェクトにエラーを登録し、別のサービスでエラーが検出されたかどうかを判別できます。

すなわち

JsonValidation.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'}, 'Invalid Json Syntax - key not double quoted');

UserOfData.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'});

これは戻ります:

['Invalid Json Syntax - key not double quoted']

ながら

ErrorSvc({id: 1, json: '{"attr": "not-valid"}'});

これは戻ります

[]

0

隠しシークレットプロパティを defineProperty enumerable: false

それは非常に速く動作します

  • 最初の読み取りuniqueId:1,257,500 ops / s
  • その他すべて:309,226,485 ops / s
var nextObjectId = 1
function getNextObjectId() {
    return nextObjectId++
}

var UNIQUE_ID_PROPERTY_NAME = '458d576952bc489ab45e98ac7f296fd9'
function getObjectUniqueId(object) {
    if (object == null) {
        return null
    }

    var id = object[UNIQUE_ID_PROPERTY_NAME]

    if (id != null) {
        return id
    }

    if (Object.isFrozen(object)) {
        return null
    }

    var uniqueId = getNextObjectId()
    Object.defineProperty(object, UNIQUE_ID_PROPERTY_NAME, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: uniqueId,
    })

    return uniqueId
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.