두 객체 사이의 일반적인 깊은 차이
두 개의 객체가 있습니다 : oldObj
및 newObj
.
의 데이터 oldObj
는 양식을 채우는 데 사용되었으며 newObj
사용자가이 양식의 데이터를 변경하여 제출 한 결과입니다.
두 물체 모두 깊습니다. 그들은 객체 또는 객체의 배열 등의 속성을 가지고 있습니다-n 레벨 깊이가 될 수 있으므로 diff 알고리즘은 재귀 적이어야합니다.
지금은 단지에서 (추가와 같이 / 업데이트 / 삭제) 변경이 있었는지 알아낼 필요 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'}] and [{a:'hey'},1,[3,{c: 1},2]]
동일한 것으로 간주하지 않는다는 것입니다. 요소의 순서가 같지 않으면 배열이 동일 하지 않다고 생각 하기 때문입니다. 물론 필요한 경우 변경할 수 있습니다. 또한이 코드는 전달 된 기본 값 (이 작업은 "compareValues"메소드에 의해 수행됨)에 따라 임의의 방식으로 diff 오브젝트를 형식화하는 데 사용되는 인수로 기능을 수행하도록 추가로 향상 될 수 있습니다.
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);
밑줄을 사용하여 간단한 차이점 :
var o1 = {a: 1, b: 2, c: 2},
o2 = {a: 2, b: 1, c: 2};
_.omit(o1, function(v,k) { return o2[k] === v; })
o1
해당 부분 이 일치하지만 다음과 같은 값이 다릅니다 o2
.
{a: 1, b: 2}
깊은 차이가 있으면 다릅니다.
function diff(a,b) {
var r = {};
_.each(a, function(v,k) {
if(b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v)
? _.diff(v, b[k])
: v
;
});
return r;
}
주석에서 @Juhana가 지적한 것처럼 위의 내용은 diff a-> b이며 되돌릴 수 없습니다 (b의 추가 속성은 무시 됨). 대신 a-> b-> a를 사용하십시오.
(function(_) {
function deepDiff(a, b, r) {
_.each(a, function(v, k) {
// already checked this or equal...
if (r.hasOwnProperty(k) || b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
});
}
/* the function */
_.mixin({
diff: function(a, b) {
var r = {};
deepDiff(a, b, r);
deepDiff(b, a, r);
return r;
}
});
})(_.noConflict());
전체 example + tests + mixins에 대해서는 http://jsfiddle.net/drzaus/9g5qoxwj/ 를 참조하십시오
ES6 솔루션을 제공하고 싶습니다 ... 단방향 차이입니다. 즉, 키와 값이 대응 o2
하는 키 / 값을 반환합니다 o1
.
let o1 = {
one: 1,
two: 2,
three: 3
}
let o2 = {
two: 2,
three: 3,
four: 4
}
let diff = Object.keys(o2).reduce((diff, key) => {
if (o1[key] === o2[key]) return diff
return {
...diff,
[key]: o2[key]
}
}, {})
Lodash 사용하기 :
_.mergeWith(oldObj, newObj, function (objectValue, sourceValue, key, object, source) {
if ( !(_.isEqual(objectValue, sourceValue)) && (Object(objectValue) !== objectValue)) {
console.log(key + "\n Expected: " + sourceValue + "\n Actual: " + objectValue);
}
});
키 / 객체 / 소스를 사용하지 않지만 액세스 해야하는 경우 키를 남겨 두었습니다. 객체 비교는 콘솔이 가장 바깥 쪽 요소에서 가장 안쪽 요소까지 콘솔의 차이점을 인쇄하지 못하게합니다.
배열을 처리하기 위해 내부에 논리를 추가 할 수 있습니다. 아마도 배열을 먼저 정렬하십시오. 이것은 매우 유연한 솔루션입니다.
편집하다
lodash 업데이트로 인해 _.merge에서 _.mergeWith로 변경되었습니다. 변경 사항을 확인한 Aviron에게 감사합니다.
다음은 두 JavaScript 객체 사이의 차이점을 찾는 데 사용할 수있는 JavaScript 라이브러리입니다.
깃 허브 URL : https://github.com/cosmicanant/recursive-diff
Npmjs URL : https://www.npmjs.com/package/recursive-diff
브라우저와 Node.js에서 재귀 -diff 라이브러리를 사용할 수 있습니다. 브라우저의 경우 다음을 수행하십시오.
<script type="text" src="index.js"/>
<script type="text/javascript">
var ob1 = {a:1, b: [2,3]};
var ob2 = {a:2, b: [3,3,1]};
var delta = diff.getDiff(ob1,ob2);
/* console.log(delta) will dump following data
{
'/a':{operation:'update',value:2}
'/b/0':{operation:'update',value:3},
'/b/2':{operation:'add',value:1},
} */
var ob3 = diff.applyDiff(ob1, delta); //expect ob3 is deep equal to ob2
</script>
node.js에서 'recursive-diff'모듈이 필요하고 아래처럼 사용할 수 있습니다.
var diff = require('recursive-diff');
var ob1 = {a: 1}, ob2: {b:2};
var diff = diff.getDiff(ob1, ob2);
요즘에는 사용할 수있는 모듈이 꽤 있습니다. 내가 찾은 수많은 diffing 모듈에 만족하지 않았기 때문에 최근 에이 작업을 수행하기 위해 모듈을 작성했습니다. 해당 호출 odiff
: https://github.com/Tixit/odiff . 또한 가장 인기있는 모듈과 readme에서 허용되지 않는 이유를 나열했습니다 . 원하는 속성이없는 odiff
경우 살펴볼 수 있습니다 odiff
. 예를 들면 다음과 같습니다.
var a = [{a:1,b:2,c:3}, {x:1,y: 2, z:3}, {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]
var diffs = odiff(a,b)
/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
{type: 'set', path:[1,'y'], val: '3'},
{type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/
설명하는 작업을 수행하기 위해이 코드를 사용했습니다.
function mergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
if(obj2[p].constructor == Object) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
}
// Property in destination object set; update its value.
else if (Ext.isArray(obj2[p])) {
// obj1[p] = [];
if (obj2[p].length < 1) {
obj1[p] = obj2[p];
}
else {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
}
}else{
obj1[p] = obj2[p];
}
} catch (e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
그러면 기존 객체와 새 객체 간의 모든 변경 사항을 양식에서 병합하는 새 객체가 생성됩니다.
Javascript에서 "compareValue ()"라는 함수를 개발했습니다. 값이 같은지 여부를 반환합니다. 한 Object의 for 루프에서 compareValue ()를 호출했습니다. diffParams에서 두 객체의 차이를 얻을 수 있습니다.
var diffParams = {};
var obj1 = {"a":"1", "b":"2", "c":[{"key":"3"}]},
obj2 = {"a":"1", "b":"66", "c":[{"key":"55"}]};
for( var p in obj1 ){
if ( !compareValue(obj1[p], obj2[p]) ){
diffParams[p] = obj1[p];
}
}
function compareValue(val1, val2){
var isSame = true;
for ( var p in val1 ) {
if (typeof(val1[p]) === "object"){
var objectValue1 = val1[p],
objectValue2 = val2[p];
for( var value in objectValue1 ){
isSame = compareValue(objectValue1[value], objectValue2[value]);
if( isSame === false ){
return false;
}
}
}else{
if(val1 !== val2){
isSame = false;
}
}
}
return isSame;
}
console.log(diffParams);
나는 파티에 늦었다는 것을 알고 있지만 위의 답변이 도움이되지 않은 비슷한 것이 필요했습니다.
변수의 변화를 감지하기 위해 Angular의 $ watch 함수를 사용하고있었습니다. 변수에서 속성이 변경되었는지 여부를 알아야 할뿐만 아니라 변경된 속성이 계산 된 임시 필드가 아닌지 확인하고 싶었습니다. 즉, 특정 속성을 무시하고 싶었습니다.
코드는 다음과 같습니다. https://jsfiddle.net/rv01x6jo/
사용 방법은 다음과 같습니다.
// To only return the difference
var difference = diff(newValue, oldValue);
// To exclude certain properties
var difference = diff(newValue, oldValue, [newValue.prop1, newValue.prop2, newValue.prop3]);
이것이 누군가를 돕기를 바랍니다.
나는 같은 문제를 해결하기 위해 람다를 사용한다. 새로운 객체에서 무엇이 바뀌 었는지 알아야한다. 여기 내 디자인이 있습니다.
const oldState = {id:'170',name:'Ivab',secondName:'Ivanov',weight:45};
const newState = {id:'170',name:'Ivanko',secondName:'Ivanov',age:29};
const keysObj1 = R.keys(newState)
const filterFunc = key => {
const value = R.eqProps(key,oldState,newState)
return {[key]:value}
}
const result = R.map(filterFunc, keysObj1)
결과는 속성 이름이며 상태입니다.
[{"id":true}, {"name":false}, {"secondName":true}, {"age":false}]
나는 이미 내 프로젝트 중 하나에 대해 사용자 옵션으로 객체를 내부 클론과 비교하는 함수를 작성했습니다. 또한 사용자가 순수한 자바 스크립트로 잘못된 유형의 데이터를 입력하거나 제거한 경우 기본값을 확인하고 기본값으로 바꿀 수도 있습니다.
IE8에서는 100 % 작동합니다. 성공적으로 테스트되었습니다.
// ObjectKey: ["DataType, DefaultValue"]
reference = {
a : ["string", 'Defaul value for "a"'],
b : ["number", 300],
c : ["boolean", true],
d : {
da : ["boolean", true],
db : ["string", 'Defaul value for "db"'],
dc : {
dca : ["number", 200],
dcb : ["string", 'Default value for "dcb"'],
dcc : ["number", 500],
dcd : ["boolean", true]
},
dce : ["string", 'Default value for "dce"'],
},
e : ["number", 200],
f : ["boolean", 0],
g : ["", 'This is an internal extra parameter']
};
userOptions = {
a : 999, //Only string allowed
//b : ["number", 400], //User missed this parameter
c: "Hi", //Only lower case or case insitive in quotes true/false allowed.
d : {
da : false,
db : "HelloWorld",
dc : {
dca : 10,
dcb : "My String", //Space is not allowed for ID attr
dcc: "3thString", //Should not start with numbers
dcd : false
},
dce: "ANOTHER STRING",
},
e: 40,
f: true,
};
function compare(ref, obj) {
var validation = {
number: function (defaultValue, userValue) {
if(/^[0-9]+$/.test(userValue))
return userValue;
else return defaultValue;
},
string: function (defaultValue, userValue) {
if(/^[a-z][a-z0-9-_.:]{1,51}[^-_.:]$/i.test(userValue)) //This Regex is validating HTML tag "ID" attributes
return userValue;
else return defaultValue;
},
boolean: function (defaultValue, userValue) {
if (typeof userValue === 'boolean')
return userValue;
else return defaultValue;
}
};
for (var key in ref)
if (obj[key] && obj[key].constructor && obj[key].constructor === Object)
ref[key] = compare(ref[key], obj[key]);
else if(obj.hasOwnProperty(key))
ref[key] = validation[ref[key][0]](ref[key][1], obj[key]); //or without validation on user enties => ref[key] = obj[key]
else ref[key] = ref[key][1];
return ref;
}
//console.log(
alert(JSON.stringify( compare(reference, userOptions),null,2 ))
//);
/ * 결과
{
"a": "Defaul value for \"a\"",
"b": 300,
"c": true,
"d": {
"da": false,
"db": "Defaul value for \"db\"",
"dc": {
"dca": 10,
"dcb": "Default value for \"dcb\"",
"dcc": 500,
"dcd": false
},
"dce": "Default value for \"dce\""
},
"e": 40,
"f": true,
"g": "This is an internal extra parameter"
}
*/
sbgoran의 답변에서보다 확장되고 단순화 된 기능.
이를 통해 심층 스캔이 가능하고 어레이의 유사성을 찾을 수 있습니다.
var result = objectDifference({
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'),
h: [1,2,3,4,5]
},
{
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'),
h: [4,5,6,7,8]
});
console.log(result);
function objectDifference(obj1, obj2){
if((dataType(obj1) !== 'array' && dataType(obj1) !== 'object') || (dataType(obj2) !== 'array' && dataType(obj2) !== 'object')){
var type = '';
if(obj1 === obj2 || (dataType(obj1) === 'date' && dataType(obj2) === 'date' && obj1.getTime() === obj2.getTime()))
type = 'unchanged';
else if(dataType(obj1) === 'undefined')
type = 'created';
if(dataType(obj2) === 'undefined')
type = 'deleted';
else if(type === '') type = 'updated';
return {
type: type,
data:(obj1 === undefined) ? obj2 : obj1
};
}
if(dataType(obj1) === 'array' && dataType(obj2) === 'array'){
var diff = [];
obj1.sort(); obj2.sort();
for(var i = 0; i < obj2.length; i++){
var type = obj1.indexOf(obj2[i]) === -1?'created':'unchanged';
if(type === 'created' && (dataType(obj2[i]) === 'array' || dataType(obj2[i]) === 'object')){
diff.push(
objectDifference(obj1[i], obj2[i])
);
continue;
}
diff.push({
type: type,
data: obj2[i]
});
}
for(var i = 0; i < obj1.length; i++){
if(obj2.indexOf(obj1[i]) !== -1 || dataType(obj1[i]) === 'array' || dataType(obj1[i]) === 'object')
continue;
diff.push({
type: 'deleted',
data: obj1[i]
});
}
} else {
var diff = {};
var key = Object.keys(obj1);
for(var i = 0; i < key.length; i++){
var value2 = undefined;
if(dataType(obj2[key[i]]) !== 'undefined')
value2 = obj2[key[i]];
diff[key[i]] = objectDifference(obj1[key[i]], value2);
}
var key = Object.keys(obj2);
for(var i = 0; i < key.length; i++){
if(dataType(diff[key[i]]) !== 'undefined')
continue;
diff[key[i]] = objectDifference(undefined, obj2[key[i]]);
}
}
return diff;
}
function dataType(data){
if(data === undefined || data === null) return 'undefined';
if(data.constructor === String) return 'string';
if(data.constructor === Array) return 'array';
if(data.constructor === Object) return 'object';
if(data.constructor === Number) return 'number';
if(data.constructor === Boolean) return 'boolean';
if(data.constructor === Function) return 'function';
if(data.constructor === Date) return 'date';
if(data.constructor === RegExp) return 'regex';
return 'unknown';
}
@sbgoran 코드의 타입 스크립트 버전은 다음과 같습니다.
export class deepDiffMapper {
static VALUE_CREATED = 'created';
static VALUE_UPDATED = 'updated';
static VALUE_DELETED = 'deleted';
static VALUE_UNCHANGED ='unchanged';
protected isFunction(obj: object) {
return {}.toString.apply(obj) === '[object Function]';
};
protected isArray(obj: object) {
return {}.toString.apply(obj) === '[object Array]';
};
protected isObject(obj: object) {
return {}.toString.apply(obj) === '[object Object]';
};
protected isDate(obj: object) {
return {}.toString.apply(obj) === '[object Date]';
};
protected isValue(obj: object) {
return !this.isObject(obj) && !this.isArray(obj);
};
protected compareValues (value1: any, value2: any) {
if (value1 === value2) {
return deepDiffMapper.VALUE_UNCHANGED;
}
if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
return deepDiffMapper.VALUE_UNCHANGED;
}
if ('undefined' == typeof(value1)) {
return deepDiffMapper.VALUE_CREATED;
}
if ('undefined' == typeof(value2)) {
return deepDiffMapper.VALUE_DELETED;
}
return deepDiffMapper.VALUE_UPDATED;
}
public map(obj1: object, obj2: object) {
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 ('undefined' != typeof(obj2[key])) {
value2 = obj2[key];
}
diff[key] = this.map(obj1[key], value2);
}
for (var key in obj2) {
if (this.isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
continue;
}
diff[key] = this.map(undefined, obj2[key]);
}
return diff;
}
}
const diff = require("deep-object-diff").diff;
let differences = diff(obj2, obj1);
매주 5 만 회 이상 다운로드되는 npm 모듈이 있습니다 : https://www.npmjs.com/package/deep-object-diff
차이점의 표현과 같은 객체를 좋아합니다. 특히 형식이 지정되면 구조를 쉽게 볼 수 있습니다.
const diff = require("deep-object-diff").diff;
const lhs = {
foo: {
bar: {
a: ['a', 'b'],
b: 2,
c: ['x', 'y'],
e: 100 // deleted
}
},
buzz: 'world'
};
const rhs = {
foo: {
bar: {
a: ['a'], // index 1 ('b') deleted
b: 2, // unchanged
c: ['x', 'y', 'z'], // 'z' added
d: 'Hello, world!' // added
}
},
buzz: 'fizz' // updated
};
console.log(diff(lhs, rhs)); // =>
/*
{
foo: {
bar: {
a: {
'1': undefined
},
c: {
'2': 'z'
},
d: 'Hello, world!',
e: undefined
}
},
buzz: 'fizz'
}
*/
나는 두 물체의 차이를 얻는 방법을 찾으려고 여기에서 우연히 발견했다. 이것은 Lodash를 사용하는 솔루션입니다.
// Get updated values (including new values)
var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value));
// Get updated values (excluding new values)
var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value)));
// Get old values (by using updated values)
var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {});
// Get newly added values
var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key));
// Get removed values
var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key));
// Then you can group them however you want with the result
아래 코드 스 니펫 :
var last = { "authed": true, "inForeground": true, "goodConnection": false, "inExecutionMode": false, "online": true, "array": [1, 2, 3], "deep": { "nested": "value", }, "removed": "value", }; var curr = { "authed": true, "inForeground": true, "deep": { "nested": "changed", }, "array": [1, 2, 4], "goodConnection": true, "inExecutionMode": false, "online": false, "new": "value" }; // Get updated values (including new values) var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value)); // Get updated values (excluding new values) var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value))); // Get old values (by using updated values) var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {}); // Get newly added values var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key)); // Get removed values var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key)); console.log('oldValues', JSON.stringify(oldValues)); console.log('updatedValuesIncl', JSON.stringify(updatedValuesIncl)); console.log('updatedValuesExcl', JSON.stringify(updatedValuesExcl)); console.log('newCreatedValues', JSON.stringify(newCreatedValues)); console.log('deletedValues', JSON.stringify(deletedValues));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
참고 URL : https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects
'IT' 카테고리의 다른 글
배열 이름이 포인터입니까? (0) | 2020.05.14 |
---|---|
PHP 사이트 URL 프로토콜 가져 오기-http 및 https (0) | 2020.05.14 |
모든 브라우저의 사용자 에이전트가“Mozilla /”로 시작하는 이유는 무엇입니까? (0) | 2020.05.14 |
Pylint가 올바르지 않은 것으로 간주하는 조건 값에서 len (SEQUENCE)을 사용하는 이유는 무엇입니까? (0) | 2020.05.14 |
편안한 POST 응답을위한 '최상의'실습 (0) | 2020.05.14 |