9

JavaScript オブジェクトからチェックサムを作成する必要があります。
残念ながら、JavaScript のオブジェクトの順序付けのために、これを実現する簡単な方法はないようです。たとえば、次のオブジェクトを取り上げます。

var obj1 = {type:"cake",quantity:0}
  , obj2 = {quantity:0,type:"cake"};

これらのオブジェクトはデータが等しいと考えており、チェックサムを同じにしたいと考えています。オブジェクト内のデータが同じである限り、オブジェクトの順序は気にしません。
悲しいかな、JSON.stringifyそれらの両方は実際には等しくありません。オブジェクトのチェックサムを作成する唯一の方法はその文字列表現を使用することであり、JSON.stringify-ed 表現が等しくないため、私のチェックサムは等しくなりません!
私が思いついた解決策の 1 つは、次のように、定義済みのスキーマに基づいてオブジェクトを再作成することです。

var schema = ["type","quantity"];
function sortify(obj,schema){
  var n={};
  for(i in schema)
    n[schema[i]]=obj[schema[i]];
  return n
}

実行JSON.stringify(sortify(obj1,schema))==JSON.stringify(sortify(obj2,schema))すると戻りtrueます...ただし、新しいオブジェクトを作成し、データをシャッフルするという代償が伴います。

JSON.stringify私のもう 1 つの解決策は、このメソッドを、事前定義されたスキーマからキーを選択し、それらの値を文字列化して結合するメソッドに置き換えることです。関数は次のとおりです。

function smarterStringify(obj,schema){
  var s="";
  for(i in schema)
    s+=JSON.stringify(obj[schema[i]]);
  return s
}

このメソッドが正しい JSON を返さないという事実を無視すると (これは、私がやろうとしていることの例としては十分に近いものです)、最初の方法よりも速度が大幅に改善されています (少なくとも私の Chrome OS ブラウザーでは、ここで自分で確認できます: http://jsperf.com/sort-then-json-stringify-vs-smarter-stringify )、そしてもちろん、2 つのオブジェクト文字列表現が等しくなります!

しかし、何かを見逃していたのではないかと思っていたのですが、a) JavaScript GC を異常なケースに追い込んだり、b) あまりにも多くの文字列連結を実行したりしなかった、このようなもののための組み込みメソッドがずっとあったのです。私はむしろそれらをしたくありません。

4

3 に答える 3

6

を使用してキーを配列に収集し、Object.keys()その配列を並べ替えてから、既知の予測可能な順序でキー/値をチェックサムできます。ただし、ソートされたすべてのキーを一度に使用する方法がわからないJSON.stringify()ため、独自のチェックサムを実行する必要があります。

このような組み込みのメソッドは知りません。オブジェクト キーは特定の順序であることが保証されていないため、それに依存するのは安全ではありません。


プロパティ値としてネストされたオブジェクトまたは配列がない場合は、次のようにすることができます。

// creates an array of alternating property name, property value
// with properties in sorted order
// then stringify's that array
function stringifyPropsInOrder(obj) {
    var keys = Object.keys(obj).sort();
    var output = [], prop;
    for (var i = 0; i < keys.length; i++) {
        prop = keys[i];
        output.push(prop);
        output.push(obj[prop]);
    }
    return JSON.stringify(output);
}

function compareObjects(a, b) {
    return stringifyPropsInOrder(a) === stringifyPropsInOrder(b);
}

より高速なパフォーマンスが必要な場合は、文字列化する必要はありません (ここではコードを節約するために行っただけです)。フラット化された配列を返すだけでoutput、配列を直接比較できます。


オブジェクトをプロパティ値として埋め込むことができる場合は、それらをプロパティ/値の同じフラット化された配列に再帰的に展開するために、さらに作業を行う必要があります。

于 2014-07-23T17:35:09.513 に答える
5

オブジェクトをその場で比較する関数を作成することもできます。

function compareObjects(a, b) {
  var akeys = Object.keys(a);
  var bkeys = Object.keys(b);
  var len = akeys.length;
  if (len != bkeys.length) return false;
  for (var i = 0; i < len; i++) {
    if (a[akeys[i]] !== b[akeys[i]]) return false;
  }
  return true;
}

これは、それらが渡されたオブジェクトであり、単純なフラット オブジェクトであると想定しています。これらの仮定をチェックし、サブオブジェクトが等しいかどうかを再帰的にチェックするロジックを追加できます。

于 2014-07-23T17:50:13.653 に答える