ES6 has a lot of functions including assign and others. But is there a method to get a list of properties that are different from one object to the next?
For example, if I have a component with two states. The default state has 100 properties that define it. State two there are only 10 properties that change. Let's say I get 2 objects containing all 100 properties. I want to create object 3 that has only the 10 properties that have changed (actually not only the properties that changed but the properties on the second object - see update).
The second object keeps all its unique properties and overrides the properties in the first.
I thought Object.assign()
might do this but I don't think so.
var object = {name:Fred, age: 20, weight: 100};
var object2 = {name:Fred, age: 21, weight: 120};
function getChangesFromObjectTwo(object1, object2) {
return object;
}
// returns {age:21, weight: 120};
var changes = getChangesFromObjectTwo(object, object2);
UPDATE:
Great answers. I wasn't specific enough... If object2 has additional properties they should show on the returned object.
var object = {name:Fred, age: 20, weight: 100};
var object2 = {name:Fred, age: 21, weight: 120, height: 70};
function getChangesFromObjectTwo(object1, object2) {
return object;
}
// returns {age:21, weight: 120, height: 70};
var changes = getChangesFromObjectTwo(object, object2);
Doesn't have to be ES6, but you can implement it like this:
var object = {name: 'Fred', age: 20, weight: 100};
var object2 = {name: 'Fred', age: 21, weight: 120, height: 70};
function getChangesFromObjectTwo(source, target) {
return Object.fromEntries(Object.entries({...source, ...target})
.filter(([key, value]) => !Object.is(source[key], value)));
}
// returns {age:21, weight: 120};
var changes = getChangesFromObjectTwo(object, object2);
console.log(changes);
Added properties also included
P.S. Using Object.is to bypass NaN problem
Assuming that keys are identical in both objects o1
and o2
, you can just use Object.keys()
with a a reduce()
operation:
Object.keys(o2).reduce((a, k) => (o1[k] !== o2[k] && (a[k] = o2[k]), a), {});
Full snippet:
const object1 = {name:'Fred', age: 20, weight: 100};
const object2 = {name:'Fred', age: 21, weight: 120};
function getChanges(o1, o2) {
return Object.keys(o2)
.reduce((a, k) => (o1[k] !== o2[k] && (a[k] = o2[k]), a), {});
}
console.log(getChanges(object1, object2));
Or if you're working in an environment that supports Object.entries()
, you can avoid a couple of lookups:
Object.entries(o2).reduce((a, [k, v]) => (o1[k] !== v && (a[k] = v), a), {});
Full snippet:
const object1 = {name:'Fred', age: 20, weight: 100};
const object2 = {name:'Fred', age: 21, weight: 120};
function getChanges(o1, o2) {
return Object.entries(o2)
.reduce((a, [k, v]) => (o1[k] !== v && (a[k] = v), a), {});
}
console.log(getChanges(object1, object2));
I believe Proxy is the tool you are looking for.
In your case, if you have
const defaultObject = {name: "Fred", age: 20, weight: 100}; // 100+ properties
var clonedObject = {...defaultObject}; // shallow copy
you can create monitor object and proxy object for them:
var monitor = {};
const proxy = new Proxy(clonedObject, {
set: function(obj, prop, value) {
obj[prop] = value;
if(defaultObject[prop]!==value) monitor[prop] = value;
else delete monitor[prop];
}
});
Now if you change anything in proxy...
proxy.age = 21;
proxy.weight = 120;
proxy.age = 20; // restore default
proxy.height = 70; // new value
...you can see the changes in monitor
console.log(monitor); // weight: 120, height: 70
console.log(clonedObject); // proxy passes the changes to clonedObject
Updated snippet you requested:
const defaultObject = {name: "Fred", age: 20, weight: 100};
var clonedObject = {...defaultObject}; // shallow copy
var monitor = {};
const proxy = new Proxy(clonedObject, {
set: function(obj, prop, value) {
obj[prop] = value;
if(defaultObject[prop]!==value) monitor[prop] = value;
else delete monitor[prop];
}
});
proxy.age = 21;
proxy.weight = 120;
proxy.age = 20; // restore default
proxy.height = 70; // new value
console.log(monitor); // weight: 120, height: 70
console.log(clonedObject);
Object.assign
does the opposite of what you want: it modifies an object based on an object listing changes.
There's no built-in function that does it, but you can easily implement your own.
For a single level depth observation, it should be enough to:
function getChangesFromObjectTwo(obj1, obj2){
//Using Set to create an unique list
return [...new Set([
...Reflect.ownKeys(obj1),
...Reflect.ownKeys(obj2)
])]
.map(k => [k, obj1[k], obj2[k]])
.filter(([, v1, v2]) => v1 !== v2)
.reduce((acc, [k, , v]) => (
acc[k] = v,
acc
), {})
}
var object = {name:"Fred", age:20, weight: 100};
var object2 = {name:"Fred", age:21, weight: 120, height: 70};
console.log(getChangesFromObjectTwo(object, object2));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With