64

アプリケーションにノード、モカ、チャイを使用しています。返された結果データ プロパティが、モデル オブジェクトの 1 つと同じ「オブジェクトのタイプ」であることをテストしたいと思います (chai のインスタンスに非常に似ています)。2 つのオブジェクトのプロパティ名のセットが同じであることを確認したいだけです。プロパティの実際の値には特に興味がありません。

以下のようなモデル Person があるとしましょう。results.data に、予想されるモデルと同じプロパティがすべて含まれていることを確認したいと思います。したがって、この場合、firstName と lastName を持つ Person です。

したがって、results.data.lastNameresults.data.firstName両方が存在する場合は、true を返す必要があります。いずれかが存在しない場合は、false を返す必要があります。ボーナスは、results.data に results.data.surname のような追加のプロパティがある場合、姓が Person に存在しないため false を返すことです。

このモデル

function Person(data) {
  var self = this;
  self.firstName = "unknown";
  self.lastName = "unknown";

  if (typeof data != "undefined") {
     self.firstName = data.firstName;
     self.lastName = data.lastName;
  }
}
4

7 に答える 7

117

単純なデータをシリアル化して、等しいかどうかを確認できます。

data1 = {firstName: 'John', lastName: 'Smith'};
data2 = {firstName: 'Jane', lastName: 'Smith'};
JSON.stringify(data1) === JSON.stringify(data2)

これはあなたに次のようなものを与えるでしょう

'{firstName:"John",lastName:"Smith"}' === '{firstName:"Jane",lastName:"Smith"}'

関数として...

function compare(a, b) {
  return JSON.stringify(a) === JSON.stringify(b);
}
compare(data1, data2);

編集

あなたが言うようにチャイを使用している場合は、http://chaijs.com/api/bdd/#equal-sectionをチェックしてください

編集2

キーを確認したいだけなら...

function compareKeys(a, b) {
  var aKeys = Object.keys(a).sort();
  var bKeys = Object.keys(b).sort();
  return JSON.stringify(aKeys) === JSON.stringify(bKeys);
}

それをする必要があります。

于 2013-01-16T21:58:01.227 に答える
48

2 ここでは短いES6可変長バージョン:

function objectsHaveSameKeys(...objects) {
   const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []);
   const union = new Set(allKeys);
   return objects.every(object => union.size === Object.keys(object).length);
}

ちょっとしたパフォーマンス テスト(MacBook Pro - 2.8 GHz Intel Core i7、Node 5.5.0):

var x = {};
var y = {};

for (var i = 0; i < 5000000; ++i) {
    x[i] = i;
    y[i] = i;
}

結果:

objectsHaveSameKeys(x, y) // took  4996 milliseconds
compareKeys(x, y)               // took 14880 milliseconds
hasSameProps(x,y)               // after 10 minutes I stopped execution
于 2016-01-27T21:00:18.270 に答える
16

両方のオブジェクトのプロパティ名が同じかどうかを確認するには、次のようにします。

function hasSameProps( obj1, obj2 ) {
  return Object.keys( obj1 ).every( function( prop ) {
    return obj2.hasOwnProperty( prop );
  });
}

var obj1 = { prop1: 'hello', prop2: 'world', prop3: [1,2,3,4,5] },
    obj2 = { prop1: 'hello', prop2: 'world', prop3: [1,2,3,4,5] };

console.log(hasSameProps(obj1, obj2));

このようにして、両方のオブジェクトの反復可能でアクセス可能なプロパティのみを確実にチェックします。

編集 - 2013.04.26:

前の関数は次のように書き直すことができます。

function hasSameProps( obj1, obj2 ) {
    var obj1Props = Object.keys( obj1 ),
        obj2Props = Object.keys( obj2 );

    if ( obj1Props.length == obj2Props.length ) {
        return obj1Props.every( function( prop ) {
          return obj2Props.indexOf( prop ) >= 0;
        });
    }

    return false;
}

このようにして、両方のオブジェクトが同じ数のプロパティを持っていることを確認します (そうでない場合、オブジェクトは同じプロパティを持っていないため、論理 false を返す必要があります)。数が一致する場合は、それらが同じかどうかを確認します。プロパティ。

ボーナス

考えられる機能強化は、すべてのプロパティで一致を強制するための型チェックも導入することです。

于 2013-01-16T23:20:44.103 に答える
2

上記のschirrmacherによって提供された関数のディープ チェック バージョンを次に示します。以下は私の試みです。ご注意ください:

  • 解決策はnullをチェックせず、防弾ではありません
  • 私はそれをテストしていません。おそらく、schirrmacher または OP がそれを行い、コミュニティで共有できます。
  • 私はJSの専門家ではありません:)。
function objectsHaveSameKeys(...objects) {
  const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), [])
  const union = new Set(allKeys)
  if (union.size === 0) return true
  if (!objects.every((object) => union.size === Object.keys(object).length)) return false

  for (let key of union.keys()) {
    let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
    if (!objectsHaveSameKeys(...res)) return false
  }
  return true
}

更新 1

私のコンピューターでは、再帰的なディープ チェック バージョンの 90% の改善が達成されconcat()ましたSet()。schirrmacher による元のシングル レベル バージョンに対する同じ最適化でも、最大 40% の改善が達成されています。

最適化されたディープ チェックのパフォーマンスは、最適化されたシングル レベル バージョンと非常に似ています。

function objectsHaveSameKeysOptimized(...objects) {
  let union = new Set();
  union = objects.reduce((keys, object) => keys.add(Object.keys(object)), union);
  if (union.size === 0) return true
  if (!objects.every((object) => union.size === Object.keys(object).length)) return false

  for (let key of union.keys()) {
    let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
    if (!objectsHaveSameKeys(...res)) return false
  }
  return true
}

性能比較

var x = {}
var y = {}
var a = {}
for (var j = 0; j < 10; ++j){
  a[j] = j
}

for (var i = 0; i < 500000; ++i) {
  x[i] = JSON.parse(JSON.stringify(a))
  y[i] = JSON.parse(JSON.stringify(a))
}

let startTs = new Date()
let result = objectsHaveSameKeys(x, y)
let endTs = new Date()
console.log('objectsHaveSameKeys = ' + (endTs - startTs)/1000)

結果

A: 再帰/ディープチェック バージョン*

  1. objectsHaveSameKeys = 5.185
  2. objectsHaveSameKeysOptimized = 0.415

B: 元の非ディープ バージョン

  1. objectsHaveSameKeysOriginalNonDeep = 0.517
  2. objectsHaveSameKeysOriginalNonDeepOptimized = 0.342
于 2021-07-30T09:44:49.497 に答える
0

underscoreJs を使用している場合は、_.isEqual 関数を使用するだけで、以下の例のように階層の各レベルですべてのキーと値を比較できます。

var object = {"status":"inserted","id":"5799acb792b0525e05ba074c","data":{"workout":[{"set":[{"setNo":1,"exercises":[{"name":"hjkh","type":"Reps","category":"Cardio","set":{"reps":5}}],"isLastSet":false,"index":0,"isStart":true,"startDuration":1469689001989,"isEnd":true,"endDuration":1469689003323,"speed":"00:00:01"}],"setType":"Set","isSuper":false,"index":0}],"time":"2016-07-28T06:56:52.800Z"}};

var object1 = {"status":"inserted","id":"5799acb792b0525e05ba074c","data":{"workout":[{"set":[{"setNo":1,"exercises":[{"name":"hjkh","type":"Reps","category":"Cardio","set":{"reps":5}}],"isLastSet":false,"index":0,"isStart":true,"startDuration":1469689001989,"isEnd":true,"endDuration":1469689003323,"speed":"00:00:01"}],"setType":"Set","isSuper":false,"index":0}],"time":"2016-07-28T06:56:52.800Z"}};

console.log(_.isEqual(object, object1));//return true

これらのキーのすべてのキーと値が両方のオブジェクトで同じである場合は true を返し、そうでない場合は false を返します。

于 2016-07-28T08:05:45.140 に答える