简体   繁体   中英

Javascript object value equality test?

I was writing a Javascript program and part of the program state was an object. I want to periodically calculate the state and compare it to the current one to decide if an event should be triggered, here's some pseudo code:

var newState = calculateState();

if (newState !== oldState) {
  triggerEvent();
}

However since the state is an object I need to do a value equality check as well as guard against null reference check. That is, if the state becomes null from non null value or the other way around, I also need to trigger the event:

if (newState === null && oldState !== null ||  // non null -> null
    newState !== null && oldState === null ||  // null -> non null
    (newState !== null && oldState !== null &&  // both non null, check members
     (newState.age !== oldState.age ||
      newState.name !== oldState.name))) {
    triggerEvent();
}

As you can see the code is really messy and ugly.

Is there a way to refactor this in Javascript?

Thank you!

If its for the sake of cleaner code, I would suggest handling the comparison between the two objects in separate a function like so:

ar newState = calculateState();

// areEqual() takes the two objects as parameters
if (areEqual(oldState, newState)) {
  triggerEvent();
}

Then decide if the two objects are equal or not in that function

// This function compares two state objects and returns true if they are valid and different
function areEqual(oldState, newState){
    return (newState === null && oldState !== null ||  // non null -> null
        newState !== null && oldState === null ||  // null -> non null
        (newState !== null && oldState !== null &&  // both non null, check members
        (newState.age !== oldState.age || newState.name !== oldState.name)));
}
if (n === null && o !== null ||  // non null -> null
    n !== null && o === null ||  // null -> non null
    (n !== null && o !== null &&  // both non null, check members
     (n.age !== o.age ||
      n.name !== o.name))) {
    triggerEvent();
}

Let's break this down (I used n and o shorthands to fit more on a line to make it easier to see what's going on -- not suggesting to use this terse convention):

n === null && o !== null ||  
n !== null && o === null

This expression can be simplified to merely: n !== o .

This works because if one is null and not the other, the expression will evaluate the true. If the objects are pointing to identical memory addresses, this will also return false (which is a good thing since their fields will also match, and we don't want to trigger events in that case).

So that gets us to here:

if (n !== o || 
   ((n !== null && o !== null) && 
    (n.age !== o.age || n.name !== o.name))) {
    triggerEvent();
}

To simplify beyond this would typically require introducing functions. It might be nice if you do this sort of thing a lot to provide an equality method for these states which compares these age and name fields. It'll also make the code less error-prone to extend if you ever add new states.

Null Swap Trick

Another trick that can sometimes be useful at the cost of a few cycles is a null swap between pairs. Example:

// if 'a' is null:
if (!a)
{
    // swap it with 'b'.
    a = [b, b = a][0];
}

// Now if 'a' is still null, both values are null.
// If 'b' is not null, both values are not null.

We can exploit it in the above code like so:

local state1 = oldState
local state2 = newState
if (!state1)
    state1 = [state2, state2 = state1][0];

if (state1) {
    // If only one of these is not null or their fields don't match:
    if (!state2 || state1.age !== state2.age || state1.name !== state2.name) {
        triggerEvent();
    }
}

A lot of whether this simplifies or complexifies will be based on how often you use this kind of terse swapping one-liner. If it's very rare, that might only add to the confusion. But this swap technique lets you write slightly more verbose code in exchange for code that's potentially more straightforward and doesn't overwhelm your brain stack quite as much (sometimes more simple code is preferable to some very complex thing that requires nested very human parsing).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM