🤩 Access a heap of free courses with a SitePoint account

Quick Tip: How to Sort an Array of Objects in JavaScript

Olayinka Omole, James Hibbard
Share

If you need to sort an array of objects into a certain order, you might be tempted to reach for a JavaScript library. But before you do, remember that you can do some pretty neat sorting with the native Array.sort function.

In this article, we’ll show you how to sort an array of objects in JavaScript using strings, numbers, and dates. We’ll also give some great tips for dealing with case-sensitivity, copies of arrays, and popular libraries that handle all of this for you.

Basic Array Sorting (and why it doesn’t work)

By default, the JavaScript Array.sort function converts each element in the array that needs to be sorted into a string, and compares them in Unicode code point order.

const foo = [9, 1, 4, 'zebroid', 'afterdeck'];
foo.sort(); // returns [ 1, 4, 9, 'afterdeck', 'zebroid' ]

const bar = [5, 18, 32, new Set, { user: 'Eleanor Roosevelt' }];
bar.sort(); // returns [ 18, 32, 5, { user: 'Eleanor Roosevelt' }, Set {} ]

You may be wondering why 32 comes before 5. Not logical, huh? Well, actually it is. This happens because each element in the array is first converted to a string, and "32" comes before "5" in Unicode order.

Using Array.sort alone wouldn’t be very useful for sorting an array of objects. Thankfully, the sort method takes an optional compareFunction parameter, which we can use to sort our array of objects.

How to Sort an Array of Objects in JavaScript

To sort an array of objects, use the sort() method with a compare function. A compareFunction applies rules to sort arrays by defined our own logic. They allow us to sort arrays of objects by strings, integers, dates, or any other custom property. We’ll cover the specifics of how compare functions work later in this article. 

For this demo we’ll use an array of singers and sort them by their band names alphabetically:

const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

The following compare function compares the (uppercase) name of each band:

function compare(a, b) {
  // Use toUpperCase() to ignore character casing
  const bandA = a.band.toUpperCase();
  const bandB = b.band.toUpperCase();

  let comparison = 0;
  if (bandA > bandB) {
    comparison = 1;
  } else if (bandA < bandB) {
    comparison = -1;
  }
  return comparison;
}

singers.sort(compare);

/* returns [
  { name: 'Steven Tyler', band: 'Aerosmith',  born: 1948 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 }
] */

To reverse the sorting order, you can invert the return value of the compare function:

function compare(a, b) {
  ...
  //invert return value by multiplying by -1
  return comparison * -1;
}

How Compare Functions work

The compareFunction returns a number which is used to determine the sorting order by comparing its two inputs (a and b). Quite simply, if the integer is less than 0, a will appear before b. If it’s greater than 0, b will appear before a. If it’s exactly 0, the original order is kept. However you determine that number is up to you.

Let’s look at a simple example with an array of numbers:

const nums = [79, 48, 12, 4];

function compare(a, b) {
  if (a > b) return 1;
  if (b > a) return -1;

  return 0;
}

nums.sort(compare);
// => 4, 12, 48, 79

We can refactor this a little, as subtracting a from b will also give us the return value. This compare function sorts an array of numbers from smallest to largest:

function compareNums(a, b) {
  return a - b;
}
nums.sort(compareNums)

It can also be represented as an arrow function without having to define the compare function elsewhere:

nums.sort((a, b) => a - b);

If you’re not familiar with arrow functions, you can read more about them here: Arrow Functions in JavaScript.

As you can see, the compare function can be written in a variety of ways and the sort() method will act as instructed.

Creating a Dynamic Sorting Function

Let’s finish up our earlier example by making this more dynamic. Let’s create a sorting function, which you can use to sort an array of objects, whose values are either strings or numbers. This function has two parameters — the key we want to sort by and the order of the results (i.e. ascending or descending):

const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
      // property doesn't exist on either object
      return 0;
    }

    const varA = (typeof a[key] === 'string')
      ? a[key].toUpperCase() : a[key];
    const varB = (typeof b[key] === 'string')
      ? b[key].toUpperCase() : b[key];

    let comparison = 0;
    if (varA > varB) {
      comparison = 1;
    } else if (varA < varB) {
      comparison = -1;
    }
    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

And this is how you’d use it:

// array is sorted by band, in ascending order by default
singers.sort(compareValues('band'));

// array is sorted by band in descending order
singers.sort(compareValues('band', 'desc'));

// array is sorted by name in ascending order
singers.sort(compareValues('name'));

// array is sorted by date if birth in descending order
singers.sort(compareValues('born', 'desc'));

In the code above, the hasOwnProperty method is used to check if the specified property is defined on each object and has not been inherited via the prototype chain. If it’s not defined on both objects, the function returns 0, which causes the sort order to remain as is (i.e. the objects remain unchanged with respect to each other).

The typeof operator is also used to check the data type of the property’s value. This allows the function to determine the proper way to sort the array. For example, if the value of the specified property is a string, a toUpperCase method is used to convert all its characters to uppercase, so character casing is ignored when sorting.

You can adjust the above function to accommodate other data types, and any other needs your script may have.

Popular Libraries for Sorting Arrays

You may not have the time or patience to create your own sorting functions in vanilla JavaScript. Time is money and code takes time. Luckily there are a variety of libraries that cater to all your array sorting needs. Here’s a short list of helper libraries that contain sorting functions… in no particular order ;)

Quick Tip: Sort an Array Of Objects by Date

To sort an array of objects by date strings all you have to do is provide a compare function that parses the date string first and subtract them from each other:

const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', birthdate: 'March 26 1948' },
  { name: 'Karen Carpenter', band: 'The Carpenters', birthdate: 'March 2 1950' },
  ...
];

function compareDates(a, b) {
  return Date.parse(new Date(a.birthdate)) - Date.parse(new Date(b.birthdate))
}

Quick tip: Sort an Array without Modifying it

Unlike many other JavaScript array functions, Array.sort is one of the methods that mutate (change) the array it sorts instead of returning a new array. To avoid this, you can create a new instance of the array to be sorted and modify that instead.  This is possible using an array method or the spread syntax to create a copy of the array.

const baz = ['My cat ate my homework', 37, 9, 5, 17];
baz.sort(); // baz array is modified
console.log(baz); // shows [ 17, 37, 5, 9, 'My cat ate my homework' ]

Using Array.slice to create a copy of the array:

const sortedBaz = baz.slice().sort(); 
// a new instance of the baz array is created and sorted

Alternatively you can use the spread operator for the same effect:

const sortedBaz = [...baz].sort(); 
// a new instance of the baz array is created and sorted

The output is the same in both cases and can be used before sorting any array of objects.

console.log(baz); // ['My cat ate my homework', 37, 9, 5, 17];
console.log(sortedBaz); // [ 17, 37, 5, 9, 'My cat ate my homework' ]

Quick tip: A Case-Insensitive Way to Sort Arrays by Strings

In our earlier example, we wanted to sort an array of objects, whose values are either strings or numbers. If, however, you know that you’ll only be dealing with objects whose values are strings, you can tidy up the code a little using JavaScript’s localeCompare method.

This method returns a number indicating whether a string comes before, after, or is the same as a given string in the sort order. It enables a case-insensitive sort of an array:

['bjork', 'Bjork', 'Björk'].sort();
// [ 'Bjork', 'Björk', 'bjork' ]

['bjork', 'Bjork', 'Björk'].sort((a, b) => a.localeCompare(b));
//  [ 'bjork', 'Bjork', 'Björk' ]

In terms of our compareValues function, that means we could write:

function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) return 0;
    const comparison = a[key].localeCompare(b[key]);

    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

You can read more about localeCompare over on MDN.

Conclusion

So there you have it — a short introduction to sorting an array of objects using vanilla JavaScript. Although many libraries offer this kind of dynamic sorting ability, as demonstrated, it’s not all that hard to implement this functionality yourself. Plus it’s good to understand what is going on under the hood.

To build the most comprehensive understanding of native JavaScript’s foundations, we recommend JavaScript: Novice to Ninja. Learn JavaScript, including ES6, from the ground up and put your new knowledge into practice by building along with a range of projects.