3

I have an array that could contain objects. Objects can either be added to it or have a property modified. I want to check if the array has changed at all (could be element(s) added or simply just have one object have a key changed), and then update the DB based on the potential change.

Just wanna know if what I have will cover all cases and/or if there is a better way to do it.

const origArrayCopy = JSON.stringify(origArray);

someFnThatPotentiallyChanges(origArray);

if (origArrayCopy !== JSON.stringify(origArray)) {
    updateDB(arr);
} else {
    console.log('NO DIFF');
}

And here's a jsFiddle I created to test around with https://jsfiddle.net/j4eqwmp6/

Converting the object to a string using stringify should account for deep-nested changes, right? Any insights on this implementation and is there now a more appropriate way to do it?

9
  • 2
    JSON.stringify() might show a change even when nothing has actually changed, because order of elements changed. Commented Jan 17, 2020 at 14:58
  • See stackoverflow.com/questions/201183/… for more reliable ways to compare objects. Commented Jan 17, 2020 at 14:59
  • 1
    I think it should be quite rare that a sequence of add/remove operations leaves the array with the same objects in a different order, or for a sequence of object property changes to leave an object with the same properties but in a different iteration order. Since the purpose is to decide whether to do a database update, a few rare false positives is probably better than a less efficient algorithm which checks for unordered equality. My opinion is that JSON.stringify should be fine for this task. Commented Jan 17, 2020 at 15:26
  • 1
    {"foo": 1, "bar": 2} and {"bar": 2, "foo": 1} are different JSON, but same objects. Commented Jan 17, 2020 at 15:45
  • 1
    Agree with @kaya3 that it's OK if false positives are acceptable. Commented Jan 17, 2020 at 15:46

1 Answer 1

1

Using JSON.stringify is certainly a possibility.

An alternative, is to wrap the object (array) in a proxy, and do that for every nested object as well. Then trap all actions that mutate those objects.

Here is how that could look:

function monitor(obj, cb) {
    if (Object(obj) !== obj) return obj;
    for (let key of Object.keys(obj)) {
        obj[key] = monitor(obj[key], cb);
    }
    return new Proxy(obj, {
        defineProperty(...args) {
            cb();
            return Reflect.defineProperty(...args);
        },
        deleteProperty(...args) {
            cb();
            return Reflect.deleteProperty(...args);
        },
        set(...args) {
            cb();
            return Reflect.set(...args);
        }
    });
};

// Example array
let origArray = [{x: 1}, { child: { y: 1} }];

// Activate the proxy:
let dirty = false;
origArray = monitor(origArray, () => dirty = true);

// Perform a mutation
origArray[1].child.y++;

console.log(dirty); // true
console.log(origArray);

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.