[解決済み】2つのオブジェクト間の一般的な深い差分
質問
2つのオブジェクトがあります。
oldObj
と
newObj
.
のデータは
oldObj
はフォームに入力するために使用され
newObj
は、ユーザーがこのフォームのデータを変更し、送信した結果です。
つまり、オブジェクトやオブジェクトの配列などのプロパティを持ち、その深さはn階層になります。
今、必要なのは、何が変更されたか(追加、更新、削除など)だけでなく
oldObj
から
newObj
ということではなく、どのように表現するのがベストなのか。
今までの私の考えは、ただ単に
genericDeepDiffBetweenObjects
メソッドで、フォーム上のオブジェクトを返します。
{add:{...},upd:{...},del:{...}}
しかし、その時、私は考えました。
そこで...これを実現するライブラリやコードをご存知の方、また、(JSONシリアライズ可能な方法で)違いを表現するさらに良い方法をご存知の方はいらっしゃいませんか?
更新しました。
更新されたデータを表現するために、より良い方法を考えました。
newObj
しかし、すべてのプロパティ値をフォーム上のオブジェクトに変換します。
{type: '<update|create|delete>', data: <propertyValue>}
ということは
newObj.prop1 = 'new value'
と
oldObj.prop1 = 'old value'
を設定することになります。
returnObj.prop1 = {type: 'update', data: 'new value'}
アップデート2
配列のプロパティになると、本当に厄介なことになります。
[1,2,3]
と等しいとみなされるはずです。
[2,3,1]
文字列やint型、bool型のような値ベースの配列では簡単ですが、オブジェクトや配列のような参照型の配列になると、扱いが非常に難しくなります。
等しく見つかるはずの配列の例。
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
このような深い値の等価性をチェックするのはかなり複雑なだけでなく、そうなるかもしれない変化を表現する良い方法を見つけ出すのも大変です。
どのように解決するのか?
私はあなたが望むことを行っている小さなクラスを書いたので、テストすることができます。 こちら .
ただ、あなたの提案と違うのは、私は以下のことを考慮に入れていないことです。
[1,[{c: 1},2,3],{a:'hey'}]
そして
[{a:'hey'},1,[3,{c: 1},2]]
というのは、配列は要素の順番が同じでないと等しくならないと思うからです。もちろん、これは必要に応じて変更することができます。また、このコードをさらに拡張して、渡されたプリミティブ値に基づいて diff オブジェクトを任意の方法でフォーマットするための関数を引数に取ることもできます(現在この仕事は "compareValues" メソッドによって行われています)。
var deepDiffMapper = function () {
return {
VALUE_CREATED: 'created',
VALUE_UPDATED: 'updated',
VALUE_DELETED: 'deleted',
VALUE_UNCHANGED: 'unchanged',
map: function(obj1, obj2) {
if (this.isFunction(obj1) || this.isFunction(obj2)) {
throw 'Invalid argument. Function given, object expected.';
}
if (this.isValue(obj1) || this.isValue(obj2)) {
return {
type: this.compareValues(obj1, obj2),
data: obj1 === undefined ? obj2 : obj1
};
}
var diff = {};
for (var key in obj1) {
if (this.isFunction(obj1[key])) {
continue;
}
var value2 = undefined;
if (obj2[key] !== undefined) {
value2 = obj2[key];
}
diff[key] = this.map(obj1[key], value2);
}
for (var key in obj2) {
if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
continue;
}
diff[key] = this.map(undefined, obj2[key]);
}
return diff;
},
compareValues: function (value1, value2) {
if (value1 === value2) {
return this.VALUE_UNCHANGED;
}
if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
return this.VALUE_UNCHANGED;
}
if (value1 === undefined) {
return this.VALUE_CREATED;
}
if (value2 === undefined) {
return this.VALUE_DELETED;
}
return this.VALUE_UPDATED;
},
isFunction: function (x) {
return Object.prototype.toString.call(x) === '[object Function]';
},
isArray: function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
},
isDate: function (x) {
return Object.prototype.toString.call(x) === '[object Date]';
},
isObject: function (x) {
return Object.prototype.toString.call(x) === '[object Object]';
},
isValue: function (x) {
return !this.isObject(x) && !this.isArray(x);
}
}
}();
var result = deepDiffMapper.map({
a: 'i am unchanged',
b: 'i am deleted',
e: {
a: 1,
b: false,
c: null
},
f: [1, {
a: 'same',
b: [{
a: 'same'
}, {
d: 'delete'
}]
}],
g: new Date('2017.11.25')
}, {
a: 'i am unchanged',
c: 'i am created',
e: {
a: '1',
b: '',
d: 'created'
},
f: [{
a: 'same',
b: [{
a: 'same'
}, {
c: 'create'
}]
}, 1],
g: new Date('2017.11.25')
});
console.log(result);
関連
-
[解決済み] let "と "var "の使い分けは?
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] JavaScriptで文字列をbooleanに変換するにはどうしたらいいですか?
-
[解決済み] 2つのJavaScriptオブジェクトのプロパティを動的にマージするにはどうすればよいですか?
-
[解決済み] HTML5のlocalStorageにオブジェクトを格納する方法は?
-
[解決済み] JavaScriptで2つの日付を比較する
-
[解決済み] JavaScriptで2つの数値の間の乱数を生成する
-
[解決済み】オブジェクトの配列を文字列のプロパティ値でソートする
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】JavaScriptのgetElementByNameが機能しない
-
[解決済み】最大呼び出しスタックサイズ超過エラーとその修正方法とは?
-
[解決済み】SyntaxError: ChromeのJavascriptコンソールでUnexpected Identifierが発生する。
-
[解決済み】SyntaxError: JSON の位置 1 に予期しないトークン o があります。
-
[解決済み】XMLパースエラー:ルート要素が見つからない コンソールの場所 FF
-
[解決済み】ES6マップオブジェクトをソートすることは可能ですか?
-
[解決済み] Uncaught (in promise) TypeError: フェッチに失敗してCorsエラー
-
[解決済み] JavaScriptでのオブジェクト比較 [重複]
-
[解決済み] 2つのJavaScriptオブジェクトの等質性を判断する方法は?
-
[解決済み] JavaScriptのオブジェクトの属性を数えるにはどうしたらいいですか?[重複しています]