Comparing Two Javascript Objects

Recently, I was faced with a problem where I needed to compare two Javascript objects. My initial strategy was to convert them to JSON and compare the JSON strings.

Sort of like this:

var a = JSON.stringify(person1);//'{"firstName":"JP","lastName":"Richardson"}'
var b = JSON.stringify(person2);//'{"firstName":"JP","lastName":"Richardson"}'

assert(a === b);

Simple enough, right?

Not so fast. I encountered a case like this:

var a = JSON.stringify(person1);//'{"firstName":"JP","lastName":"Richardson"}'
var b = JSON.stringify(person2);//'{"lastName":"Richardson","firstName":"JP"}'

assert(a === b);

The data is the same, but the string is different. Fortunately, Stackoverflow had a nice Javascript object comparison algorithm to dump into my app.

Object.prototype.equals = function(x)
{
  var p;
  for(p in this) {
      if(typeof(x[p])=='undefined') {return false;}
  }

  for(p in this) {
      if (this[p]) {
          switch(typeof(this[p])) {
              case 'object':
                  if (!this[p].equals(x[p])) { return false; } break;
              case 'function':
                  if (typeof(x[p])=='undefined' ||
                      (p != 'equals' && this[p].toString() != x[p].toString()))
                      return false;
                  break;
              default:
                  if (this[p] != x[p]) { return false; }
          }
      } else {
          if (x[p])
              return false;
      }
  }

  for(p in x) {
      if(typeof(this[p])=='undefined') {return false;}
  }

  return true;
}

Test passed. I eventually hit a situation where I had some code with an Object that had a Person prototype and some data that came from JSON. Kinda like this:

var person1 = new Person('JP', 'Richardson');
var person2 = JSON.parse('{"firstName":"JP","lastName":"Richardson"}');

//deepEquals is code snippet above ^
person1.deepEquals(person2); // <--- THIS FAILS

I only cared about comparing the data. The methods associated with the object (Prototype) didn’t matter. Let’s modify the above algorithm. I use CoffeeScript. Here’s the modification:

Object::jsonEquals = (x) ->
  #we do this because two objects may have the same data fields and data but different prototypes
  x1 = JSON.parse(JSON.stringify(this))
  x2 = JSON.parse(JSON.stringify(x))

  p = null
  for p of x1
    return false if typeof (x2[p]) is 'undefined'
  for p of x1
    if x1[p]
      switch typeof (x1[p])
        when 'object'
          return false unless x1[p].jsonEquals(x2[p])
        when 'function'
          return false if typeof (x2[p]) is 'undefined' or (p isnt 'equals' and x1[p].toString() isnt x2[p].toString())
        else
          return false  unless x1[p] is x2[p]
    else
      return false if x2[p]
  for p of x2
    return false if typeof (x1[p]) is 'undefined'
  true

This causes the situation like I described above to pass. Essentially convert to JSON to remove the prototype. I suppose you could make this more efficient my just manually setting the prototype to Object before doing the comparison, but oh well this works for the time being.

Do you use Git? If so, checkout Gitpilot to make project management and collaborating on projects seamless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Node.js Exec Like Ruby Exec and Writing a Node.js Native Add On Module

Recently, I was faced with a problem that required my Node.js programs process to execute another process and have the procoess that’s passed to the exec function completely replace the Node.js process. In short, I wanted an ‘exec’ function like Ruby’s ‘exec’ function. Unfortunately, out of the box, Node.js doesn’t support this functionality. I asked on Stackoverflow.com, and someone had a response that I should use the POSIX exec functions to solve my problem and to consider writing a native Node.js extension.


npm install kexec

You can then use it like:

var kexec = require('kexec');
kexec('top'); //you can pass any process that you want here

Here is the C++ source for Node Kexec:


#include <v8.h>
#include <node.h>
#include <cstdio>

//#ifdef __POSIX__
#include <unistd.h>
/*#else
#include <process.h>
#endif*/

using namespace node;
using namespace v8;

static Handle<Value> kexec(const Arguments& args) {
    String::Utf8Value v8str(args[0]);
    char* argv2[] = {"", "-c", *v8str, NULL};

    execvp("/bin/sh", argv2);      
    return Undefined();
}

extern "C" {
    static void init (Handle<Object> target) {
        NODE_SET_METHOD(target, "kexec", kexec);
    }

    NODE_MODULE(kexec, init);
}

As you can see, writing a C++ add on in Node.js isn’t too difficult. You can use it in your Node.js Javascript like so:

var kexec;

try {
  kexec = require("./build/default/kexec.node"); //Node.js v0.4
} catch(e) {
  kexec = require("./build/Release/kexec.node"); //Node.js v0.6
}

module.exports = kexec.kexec; //function of kexec module is named kexec

Don’t forget your wscript file, which ironically is Python code:

def set_options(opt):
  opt.tool_options("compiler_cxx")

def configure(conf):
  conf.check_tool("compiler_cxx")
  conf.check_tool("node_addon")

def build(bld):
  obj = bld.new_task_gen("cxx", "shlib", "node_addon") 
  obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE","-Wall"]
  obj.target = "kexec"
  obj.source = "src/node_kexec.cpp"

In your package.json, include this bit:

"scripts": { "install": "node-waf configure build" }

Github Sourcecode: Node.js kernel exec

I’ve also included other resources for writing a Node.js Native Add On Module:

  1. Google V8 Engine Getting Started
  2. Google V8 Embedder’s Guide
  3. How to Roll Your Own Javascript API with V8
  4. How to Write Your Own Native Node.js Extension
  5. Writing Node.js Native Extensions
  6. Node.js Native Extension with Hammer and a Prayer
  7. Mastering Node; Add Ons
  8. Node.js Documentation: Add Ons
  9. Postgres Node.js Module
  10. V8 Sample: shell.cc
  11. V8 Objects
  12. There’s C in My JavaScript
  13. Converting V8 Arguments to C++ Types

Do you use Git? If so, checkout Gitpilot to make using Git easy.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

A for-loop conversion from JavaScript to CoffeeScript

I was stumbling along StackOverflow when I ran into this question:

How can I convert a Javascript for-loop to Coffee? With this example:

for (i = 0; i < 10; i++) {
    doStuff();
}

The answer: (I’ve since edited and updated the Stackoverflow answer)

doStuff() for i in [0 .. 9]

http://jashkenas.github.com/coffee-script/#loops

This answer works for this contrived case.

What happens when you have a case like this:

for (var x = 0; x < myArray.length; ++x)
  alert(x);

What’s the answer smarty pants?
If you answered:

alert(i) for i in [0 .. myArray.length-1]

You get a pass if myArray has anything in it. What will happen if myArray is an empty (not null) array?
Go ahead and execute it. Go here to the CoffeeScript page, and paste this code in the “Try CoffeeScript”, I’ll wait.

myArray = []
alert(i) for i in [0 .. myArray.length-1]

What’s that? You say it returned “0″ and “-1″???

The secret is in the ".." which implies "=>" or "<="
and the "..." implies "&lt" or "&gt".

So this is probably what you expect:

myArray = []
alert(i) for i in [0 ... myArray.length]

It’s too bad the loops section at this time doesn’t mention this.

CoffeeScript is a great tool. Here is another tool that allows you to convert JavaScript to CoffeeScript. Try our examples here and see what the tool generates. Hint: it isn’t always optimized.

Do you use Git? If so, checkout Gitpilot to make using Git thoughtless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Follow

Get every new post delivered to your Inbox.