As a follow up to my previous post on generating signatures in JavaScript, I decided to embark on a quest to iterate on two objects, find common properties, and calculate a signature using the same signature generation logic I outlined in that post.

Real bag of magic beans, I swear.

They key to success, is you need to know what properties the objects share, this is where we enter the dynamic portion - we don't exactly know what we'll find, but we know something should be there, even if it's nulled out.

Suppose, we take Bob and Alice into our Person object again, as seen below:

var Bob = {
  id: 1,
  age: 23,
  goals: "Being human one day",
  whoami: {
      human: false,
      robot: true
  }
};

var Alice = {
    id: 2,
    age: 23,
    goals: "Being human one day",
    whoami: {
        human: false,
        robot: false
    }
};

Let's suppose our two properties we primarily use for signature generation are age and goals, as we can see they both have the same age, and same goals. This would calculate an identical signature, producing a false positive.

Iterating on shared properties

In this case, we see the objects have a whoami field, this we can use to iterate on properties they share, in order to do that, we'd rely on Object.keys and a simple nested for loop, like shown below.

// Define a "common" array, these will contain only identical properties of both objects.
var common = [];

// Get all the object keys for Bob's "whoami" field
var bob_keys = Object.keys(Bob.whoami);

// Get all the object keys for Alice's "whoami" field
var alice_keys = Object.keys(Alice.whoami);

// Begin a simple iteration of the Bobs keys, comparing immediately to Alice's keys (it is important to note, this iteration likely would not be used in production due to it's overall cost on a larger object)

for(var i = 0; i < bob_keys.length; i++) {
    var key = bob_keys[i];
    for(var j = 0; j < alice_keys.length; j++) {
           var jkey = alice_keys[j];
           if(key === jkey) {
               common.push(key);
           }
    }
}

// We now have a list of keys we can use in the "common" scope

In our loop we are iterating on Bob's keys, then iterate on Alice's inside of Bobs. It is important to note that in this example we are iterating Alice each time, in a practical production setup you should not do this, the cost can get significant on larger objects.

Checking signatures on the common object properties

Now that we have some common properties, we should iterate on them to form a LEFT comparison array, and a RIGHT comparison array. We can do that by taking the age, and goals of Bob along with the common properties of bob, and pushing them into an array called "bob_props", and likewise Alice into "alice_props", this can be done using a for loop. It's important to note, this data we should now read on the object, so we can compare it directly.

// Bobs properties
var bob_props = [];

// Alice's properties
var alice_props = [];

// Let's push our age, goals onto Bob and Alice
bob_props.push(bob.age);

bob_props.push(bob.goals);

alice_props.push(alice.age);

alice_props.push(alice.goals);

// Now, iterate on the common properties, pushing each common property into their respective array (either Bob or Alice)
common.forEach(prop => {

    // Get the value of bob.whoami[prop], for example: bob.whoami[human]
    bob_props.push(bob.whoami[prop]);
    
    // Get the value of alice.whoami[prop], for example: alice.whoami[human]
    alice_props.push(alice.whoami[prop]);
});

Now we have an array of shared properties with their respective values. Next we should be able to calculate the signature for the hash using our signature method. In order to see if we're the same object, we can do a simple conditional statement like below:

if( Person.getSignature( bob_props ) === Person.getSignature( alice_props ) ) {
    alert('They are still the same.');
}
else
{
    alert('They are not the same.');
}

What this is doing under the hood, is we're passing the Array of data to calculate the signature of, then comparing it to the other signature we generated using the same method. In our example, we expect the else condition to be hit, as they are not the same - one property "robot" is different on both objects, so our signatures would not match.

Now, you can calculate signatures on shared properties, without having to know what properties they share, this opens the door for pushing magic properties onto the objects, and still finding identical objects.

I hope you've liked this article, if you have any questions feel free to reach out!

bitwise code engineering javascript

Mike

Senior Software Engineer, Labber, Sysadmin. I make things scale rapidly. Optimize everything.

Read More