Sorting an object is one of those little things which nobody ever considers useful to know (until it becomes so), but it's proven particularly useful to me in the last few months - not necessarily for the comparison of two objects at runtime (which, thankfully, there are much quicker things for in NodeJS/JavaScript), but for the ease of reading logged data stores efficiently - especially large amounts of JSON, like that returned from certain requests. For example, if I'm looking for a specific key inside a logged object which has keys added asynchronously, I might end up looking for my specific key for a while. If the keys were sorted, I just jump straight to it.

For now we'll just look at small objects; let's consider these two objects below as our test case:

var object1 = {
    key1:'value1',
    key2:'value2'
}

var object2 = {
    key2:'value2',
    key1:'value1'
}

JSON.stringify(object1) == JSON.stringify(object2);

Of course, the above returns false - but we can use it as a test for further on, because it should return true when we use our sort method. Oh, and the reason we have to do the comparison with JSON.stringify() is due to the fact that == and === will only ever return true for an object comparison if they are the same object (and not an identical object).

For the sort, I'm going to use UnderscoreJS. I'll also post the same solution in pure JS for those people that want it. The first thing we need to focus on is getting a list of the keys in order. So, let's start with a test object. I'm just gonna throw in some random fields/types:

var object = {
    test:5,
    colour:'red',
    song:'I Believe In A Thing Called Love',
    profession:'Singer',
    gender:'Male',
    languages:{
        array: [ 'French', 'German', 'English' ]
    },
    relationships:{
        'sister':'Jasmine',
        'brother':'Ryan'
    }
}

The first thing we need to do is gain access to a list of the keys inside the object. Fortunately for us, this is pretty simple to do:

// Underscore
var keys = _.keys(object);      // ['test', 'colour', 'song', 'profession', 'gender', 'languages', 'relationships']

// JavaScript
var keys = Object.keys(object); // ['test', 'colour', 'song', 'profession', 'gender', 'languages', 'relationships']

The first thing you'll notice is that this only gives us top-level keys. This is due to the fact that the inner objects are technically different objects. Were we to call either of the above on the inner object, we would get their keys too.

Ok, so we now have a list of top-level keys in the object. Naturally, the next step is to sort these keys alphabetically, which is also pretty simple. Underscore has a nice method already available for this which makes it pretty easy, but it's also very casual to implement in pure JS.

// Underscore
var sortedKeys = _.sortBy(keys, function(key){
    return key; 
});

// JavaScript
var sortedKeys = keys.sort(function(key1, key2){
    key1 = key1.toLowerCase(), key2 = key2.toLowerCase();
    if(key1 < key2) return -1;
    if(key1 > key2) return 1;
    return 0;
})

// Both result in ['colour', 'gender', 'languages', 'profession', 'relationships', 'song', 'test']

I usually prefer Underscore here, because the sort can be neatened into a single line pretty easily - but that's obviously personal preference. So now we can see that we've moved from

[
   'test',
   'colour',
   'song',
   'profession',
   'gender',
   'languages',
   'relationships'
]

to

[
   'colour',
   'gender',
   'languages',
   'profession',
   'relationships',
   'song',
   'test'
]

We essentially have what we need to start remapping to the new object we're going to return; all we need to do is create a new object and start mapping the keys over in this new order one-by-one.

var sortedObj = {};

// Underscore
_.each(keys, function(key) {
    sortedObj[key] = object[key];
});

// JavaScript
for(var index in keys){
    var key = keys[index];
    sortedObj[key] = object[key];
}

// Resulting object
{
    'colour': 'red',
    'gender': 'Male',
    'languages': {
        'array': [
            'French',
            'German',
            'English'
        ]
    },
    'profession': 'Singer',
    'relationships': {
        'sister': 'Jasmine',
        'brother': 'Ryan'
    },
    'song': 'I Believe In A Thing Called Love',
    'test': 5
}

As you can see, all top-level keys are now sorted in alphabetical, descending, order. We're almost there. However, there are still a couple of issues, can you spot them?

Firstly, nested objects aren't touched by this code, they're copied as-is (as-are?) straight into the new object. This is a simple problem to solve though, we just put in a check for an object type and then recall the code if it's an object, to sort this too. Unfortunately though, it isn't this simple. See if you can figure out what's going to go wrong, without seeing the resulting object. I'll give you a hint, it involves Arrays.

if(typeof object[key] == 'object'){
    sortedObj[key] = sortObject(object[key]); // sortObj will be the function holding this code
} else {
    sortedObj[key] = object[key];
}

Did you figure it out? An array is of the Object type, meaning that this too will be run through the sortObject(), and because we're using for(var x in X) syntax (Underscore does this under the hood too), we're going to see the indexes in any arrays read as an object key, and it will be translated from an array to an object. If we take our example, you can see what happens:

// Before
'languages': {
    'array': [
        'French',
        'German',
        'English'
    ]
}

// After
'languages': {
    'array': {
        '0': 'French',
        '1': 'German',
        '2': 'English'
    }
}

This is technically not that bad, you would still access your elements the same way and so on, but you'd lose the array methods (e.g. .push()). Once again, however, this is extremely simple to fix. We just add a check for an Array instance alongside the object check.

if(typeof object[key] == 'object' && !(object[key] instanceof Array)){
    sortedObj[key] = sortObject(object[key]);
} else {
    sortedObj[key] = object[key];
}

This will ignore the recursion if the current object is an array, and just map it to the new object. Now that we have everything covered, let's put it all together into a simple, callable function.

// Underscore
function sortObject(object){
    var sortedObj = {},
        keys = _.keys(object);

    keys = _.sortBy(keys, function(key){
        return key;
    });

    _.each(keys, function(key) {
        if(typeof object[key] == 'object' && !(object[key] instanceof Array)){
            sortedObj[key] = sortObject(object[key]);
        } else {
            sortedObj[key] = object[key];
        }
    });

    return sortedObj;
}

// JavaScript
function sortObject(object){
    var sortedObj = {},
        keys = Object.keys(object);

    keys.sort(function(key1, key2){
        key1 = key1.toLowerCase(), key2 = key2.toLowerCase();
        if(key1 < key2) return -1;
        if(key1 > key2) return 1;
        return 0;
    });

    for(var index in keys){
        var key = keys[index];
        if(typeof object[key] == 'object' && !(object[key] instanceof Array)){
            sortedObj[key] = sortObject(object[key]);
        } else {
            sortedObj[key] = object[key];
        }
    }

    return sortedObj;
}

Now, all that we need is a simple test of what we had back at the start:

var object1 = {
	key1:'value1',
	key2:'value2'
}

var object2 = {
	key2:'value2',
	key1:'value1'
}

JSON.stringify(sortObject(object1)) === JSON.stringify(sortObject(object2));

The comparison will now report true, as we would like. So, there you have it; a simple way to sort an object by its keys in Node/JavaScript. As I mentioned earlier, you probably shouldn't be using this to compare objects because it's probably quite slow (although not noticeably), but it's pretty useful for printing two objects out if you require a further look.

If you have any questions about the above, or suggested improvements, just let me know in the comments section below.